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 2026Releases
latest 60 of 74-
6.2.123 May 2026Release notes
Open source →Security Release
This release fixes a server-side HTTP/2 vulnerability in the
Psl\H2component (GHSA-pw9p-jvrm-f7rm).Impact
Psl\H2\ServerConnectiondid not validate that the total bytes received in HTTP/2 DATA frames matched thecontent-lengthheader declared in the initial HEADERS frame, in violation of RFC 9113 §8.1.1 and §8.1.2.6. #777A 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\ServerConnectiondirectly to accept untrusted client traffic. Consumers of documented high-level PSL APIs are not affected.Patches
- Parses and validates
content-lengthon 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\StreamExceptionon 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 abuffered()block never reach the wire, and a peer that only sendsWINDOW_UPDATEafter seeing our DATA would deadlock.
Upgrade
composer require php-standard-library/psl:^6.2.1Credit
Discovered during internal review prior to public exploitation.
Release notes
Open source →security
- fix(h2): validate
content-lengthheader against received DATA on server connections, preventing HTTP/2 request smuggling onPsl\H2\ServerConnection(GHSA-pw9p-jvrm-f7rm)
-
6.2.023 May 2026Release notes
Open source →PSL 6.2.0
A massive release — three new networking stack components (HTTP, SMTP, DNS), the
EitherOrBothtype 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/Responsevalue objects with streaming bodies (ReadHandleInterface),FieldMap(ordered, case-insensitive headers with lazy index),ProtocolVersioncovering HTTP/1.0 through HTTP/3, trailers asAsync\Awaitable<FieldMap>, status/method constants per RFC 9110, andTransaction/Exchangefor 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,RedirectClientandRetryClientdecorators, per-requestSendConfiguration, SSRF protection viaDeniedDestinationsMiddleware, 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 fluentwith*()mutation, address methods acceptingstring|Mailbox|AddressList, streamingserialize()/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-levelConnectionfor protocol-level operations and high-levelTransportmanaging 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.SystemResolvermirrors 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).RacingResolverraces multiple nameservers concurrently,SplitHorizonResolverroutes by domain,SearchDomainResolverexpands short names,HostsFileResolverchecks the OS hosts file,CachedResolverdecorator with TTL-aware caching, andStaticResolverfor 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.SecureResolvervalidates RRSIG signatures,TrustChainResolverwalks DS/DNSKEY from root to target zone,CachedTrustChainResolverfor performance,StaticTrustChainResolverfor 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'sitertools::EitherOrBothand Haskell'sData.These. UnlikeEither, 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, plusleft()/right()/both()free constructors.Iter\merge_join_by/Iter\merge_join_by_key— full-outer-join stream producers yieldingEitherOrBothevents.merge_join_byis a lazy two-cursor merge over sorted inputs (O(1) memory,Comparison\Order-returning comparator).merge_join_by_keyis 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 aniterable<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— throwRuntimeExceptionif the underlying handle exceeds N bytes.FixedLengthReadHandle— read exactly N bytes, throw on premature EOF.
Plus
IO\copy_chunked()andIO\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
Collectioninterfaces and implementations (Map,Set,Vector)
Async\Sequence,KeyedSequence,Semaphore, andKeyedSemaphorenow correctly distinguish contravariant inputs from covariant outputs.HTTP/2 (
H2)- New unified
Configurationreplacing the deprecatedClientConfigurationandServerConfiguration. BothClientConnectionandServerConnectionaccept it. Client-side BDP auto-tuning is now available whenmaxReceiveWindowSizeis set on the unified config.
TCP & Type Additions
TCP\bindTo— bind to a specific local address before connecting or listening. Available on bothConnectConfigurationandListenConfigurationwithwithBindTo()builders;connect()respects it viasocket.bindto.Type\bool()— now coerces'true'/'false'string literals (thanks @veewee, #735).Type\class_string— allownullargument to assert or coerce a bareclass-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 implementsBufferedWriteHandleInterface— no data left in buffers.Async\Stateno longer captures$thisin queued callbacks, fixing delayed GC ofDeferred/Awaitablechains.URIcorrectly parses bare IPv6 addresses (e.g.,http://::1/path) asIPHostinstead of misparsing as a registered name with numeric port.H2separatesmaxConcurrent(peer's limit on our streams) frompeerMaxConcurrent(our limit on peer's streams), so client's own SETTINGS no longer limit its outgoing streams.H2\BDPEstimatoremits an initial connection-levelWINDOW_UPDATEduringinitialize(), bringing the receive window from the RFC default (65535) up toinitialWindowSizeto prevent flow-control stalls under burst concurrency.H2waiter notification copies the list before iterating and properly removes satisfied waiters — no iteration corruption or memory leaks.IO\ResourceHandleread/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— useConnectConfiguration::$bindTo/ListenConfiguration::$bindTo.H2\ClientConfigurationandH2\ServerConfiguration— use the unifiedH2\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.2Release notes
Open source →features
- feat(either-or-both): introduce
EitherOrBothcomponent - a three-variant disjoint union (Left/Right/Both) for values that may be present on either or both of two sides, inspired by Rust'sitertools::EitherOrBothand Haskell'sData.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. Fullmap/mapLeft/mapRight/mapAny/swap/proceed/apply/containsLeft/containsRightsurface;left()/right()/both()free constructors. - feat(iter): add
Iter\merge_join_byandIter\merge_join_by_key- full-outer-join stream producers that yieldEitherOrBothevents as a rewindableIter\Iterator.merge_join_byis a lazy two-cursor merge over sorted inputs (O(1) memory on first traversal,Psl\Comparison\Order-returning comparator, matching Rust'sitertools::merge_join_by);merge_join_by_keyis a hash-based variant for keyed inputs that do not need to be pre-sorted (O(|right|) memory). - feat(io): add
IO\IterableReadHandle- a streamingReadHandleInterfacethat lazily consumes aniterable<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 aReadHandleInterfaceandWriteHandleInterfaceinto 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, unlikeMemoryHandle('')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, throwingRuntimeExceptionif the underlying handle has more data than the limit allows - feat(io): add
IO\FixedLengthReadHandle- reads exactly N bytes from an underlying handle, throwingRuntimeExceptionon premature EOF - feat(io): add
IO\copy_chunked()andIO\copy_bidirectional_chunked()- variants ofIO\copy()andIO\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 inType\bool()coercion - #735 by @verweto - feat(mime): introduce
MIMEcomponent - 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
- Media type parsing, validation, and content negotiation (
- feat(message): introduce
Messagecomponent - RFC 5322 internet message construction, parsing, and serialization- Typed header fields with fluent
with*()methods (Message) per RFC 5322 - Address methods accept
string|Mailbox|AddressListfor convenience - Message body as
PartInterfacefrom the MIME component per RFC 2045 - Streaming
serialize()andparse()accepting string orReadHandleInterface - 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,AddressListwith RFC 2047 encoded-word support
- Typed header fields with fluent
- feat(smtp): introduce
SMTPcomponent - RFC 5321 SMTP client with connection pooling, TLS, and authentication- Low-level
ConnectionimplementingNetwork\StreamInterfacefor protocol-level SMTP operations - High-level
Transportmanaging 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
EnhancedStatusCodeparsing - 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
DurationorDateTimeInterface - BINARYMIME (RFC 3030), 8BITMIME (RFC 6152), SMTPUTF8 (RFC 6531) capability negotiation
- Punycode IDN encoding for internationalized domain names in addresses
- Partial recipient success with
DeliveryReportfor 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
TransportConfigurationandSendConfigurationwith fluentwith*()builders - Configurable pipelining, chunking, chunk size, and partial success behavior
- Low-level
- feat(dns): introduce
DNScomponent - async DNS resolution with full protocol supportSystemResolvermirrors 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 RacingResolverraces multiple nameservers concurrently for fastest responseSplitHorizonResolverroutes queries by domain name for split-horizon DNSSearchDomainResolverexpands short names using search domain listsHostsFileResolverchecks the OS hosts file before network queriesCachedResolverdecorator with TTL-aware caching viaCache\StoreInterfaceStaticResolverfor 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
HTTPSResolverusing the HTTP client (RFC 8484) - DNS name validation with null byte and label length enforcement
ResponseCodehelper methods:isSuccess(),isError(),isServerError(),isNameError()
- feat(dnssec): introduce
DNSSECcomponent - full DNSSEC validation chainSecureResolvervalidates RRSIG signatures on every responseTrustChainResolverwalks DS/DNSKEY chain from root to target zoneCachedTrustChainResolvercaches trust chain results for performanceStaticTrustChainResolverfor 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 Messagecomponent - version-agnostic HTTP message abstractionsRequestandResponseimmutable value objects with streaming body (ReadHandleInterface)FieldMapordered, case-insensitive header field collection with lazy indexProtocolVersionenum 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 Transactiongroups the final response with informational (1xx) responses and server push exchangesExchangerepresents a pushed request/response pair for HTTP/2 server push
- feat(http-client): introduce
HTTP Clientcomponent - async HTTP/1.1 and HTTP/2 client with connection poolingClientwith automatic protocol negotiation via ALPN (HTTP/2 preferred, HTTP/1.1 fallback)PooledConnectorwith HTTP/1.x idle connection reuse and HTTP/2 session sharing across concurrent requests- HTTP/2 multiplexing with event-driven stream dispatch via
H2Multiplexerand per-streamH2Streamstate - Transparent reconnection on connection failure (GOAWAY, TCP reset) via pool-backed reconnect closures
RedirectClientdecorator following 301/302/303/307/308 redirects with method rewriting per RFC 9110, cross-origin credential stripping, and auto-referrerRetryClientdecorator with configurable exponential backoff and jitter for transport-level failuresSendConfigurationfor per-request overrides (body size limits, TLS, protocol versions, tunnel) merged withClientConfigurationdefaultsDeniedDestinationsMiddlewarefor SSRF protection against private IP ranges (RFC 1918, RFC 4193, loopback, link-local)- Connection-level middleware via
HandlerInterface/MiddlewareInterfacechain with access to peer address and TLS state - SOCKS5 proxy support via
ClientConfiguration::$proxyusingPsl\Socks\Connector - HTTP CONNECT tunnel support via
ClientConfiguration::$tunnelwith TLS and proxy authentication noTunnelinghost 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
ResponseBodyHandleimplementingReadHandleInterface - 104 integration tests against httpbun covering methods, redirects, auth, caching, cookies, concurrency, and streaming
- feat(h2): introduce unified
Configurationreplacing deprecatedClientConfigurationandServerConfiguration- Both
ClientConnectionandServerConnectionnow acceptConfigurationin addition to their legacy config types ClientConnectionnow supports BDP auto-tuning when usingConfigurationwithmaxReceiveWindowSizeset
- Both
- feat(tcp): add
bindTooption toConnectConfigurationfor binding to a specific local address before connecting - feat(tcp): add
bindTooption toListenConfigurationfor binding to a specific local address before listening - feat(tcp): add
withBindTo()fluent builder method to bothConnectConfigurationandListenConfiguration - feat(tcp):
connect()now respectsConnectConfiguration::$bindToby setting thesocket.bindtostream context option - feat(type): Allow null argument to
Type\class_stringto assert or coerce bareclass-string
type system
- chore(types): annotate read-only template parameters with
@template-covariantacross 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,KeyedSemaphoretemplate 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()andMutableVector::getIterator()return type fromIterator<int<0, max>, T>toIterator<int, T>.
fixes
- fix(io):
IO\copy()now flushes the writer after copying if it implementsBufferedWriteHandleInterface, ensuring no data remains in an internal buffer - fix(async):
State::subscribe()andState::invokeCallbacks()no longer capture$thisin queued closures, preventing delayed garbage collection ofDeferred/Awaitablechains - fix(uri): bare IPv6 addresses (e.g.,
http://::1/path) are now correctly parsed asIPHostinstead of being misparsed as a registered name with a numeric port - fix(h2): separate
maxConcurrent(peer's limit on our streams) frompeerMaxConcurrent(our limit on peer's streams) inStreamTable, preventing the client's own SETTINGS from limiting its outgoing streams - fix(h2):
BDPEstimatornow produces an initial connection-level WINDOW_UPDATE duringinitialize()to bring the receive window from the RFC default (65535) up toinitialWindowSize, 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):
ResourceHandlereadable/writable callbacks now null out the suspension reference before callingresume(), preventing "Must call suspend() before calling throw()" errors during handle destruction - fix(io):
ResourceHandle::doRead()anddoWrite()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):
Socketclass -- useConnectConfiguration::$bindToorListenConfiguration::$bindToinstead. Will be removed in PSL 7.0. - deprecated(h2):
ClientConfiguration-- useConfigurationinstead. Will be removed in PSL 7.0. - deprecated(h2):
ServerConfiguration-- useConfigurationinstead. 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
-
6.1.223 May 2026Release notes
Open source →Security Release
This release fixes a server-side HTTP/2 vulnerability in the
Psl\H2component (GHSA-pw9p-jvrm-f7rm).Impact
Psl\H2\ServerConnectiondid not validate that the total bytes received in HTTP/2 DATA frames matched thecontent-lengthheader declared in the initial HEADERS frame, in violation of RFC 9113 §8.1.1 and §8.1.2.6. #778A 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\ServerConnectiondirectly to accept untrusted client traffic. Consumers of documented high-level PSL APIs are not affected.Patches
- Parses and validates
content-lengthon 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\StreamExceptionon 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 abuffered()block never reach the wire, and a peer that only sendsWINDOW_UPDATEafter seeing our DATA would deadlock.
Upgrade
composer require php-standard-library/psl:^6.1.2Credit
Discovered during internal review prior to public exploitation.
-
6.1.120 Mar 2026Release notes
Open source →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) becausemb_chr()returnsfalseand it was silently cast tostring. It now throwsStr\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 overStr\chr(), making both functions fully consistent. Invalid code points now throwStr\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()andfrom_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 functionimport for global PHP functions ornamespace\foo()for same-namespace functions.Documentation
Str\width(),Str\truncate(), andStr\width_slice()PHPDoc now explicitly states that width is defined bymb_strwidth()/mb_strimwidth(), and cross-references related functions likeStr\length(),Str\Grapheme\length(), andStr\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.
Release notes
Open source →fixes
- fix(str):
Str\chr()now throwsOutOfBoundsExceptionfor invalid Unicode code points instead of silently returning an empty string - fix(str):
Str\from_code_points()now validates code points and throwsOutOfBoundsExceptionfor out-of-range values, surrogates, and negative inputs instead of producing invalid UTF-8; implementation now delegates toStr\chr()for consistent behavior
other
- chore(str): clarify
width(),truncate(), andwidth_slice()PHPDoc to explicitly referencemb_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
-
6.1.019 Mar 2026Release notes
Open source →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
CompressorInterfaceorDecompressorInterface(brotli, gzip, zstd, etc.), PSL gives you four handle decorators to wire them directly into the IO system:CompressingReadHandle&CompressingWriteHandleDecompressingReadHandle&DecompressingWriteHandle
We've also included
compress()anddecompress()convenience functions for simple, one-shot operations. Under the hood, write handles implement the newBufferedWriteHandleInterfacefor explicit flushing and cancellation, while read handles accept configurable chunk sizes. Compressors automatically reset after callingfinish(), 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
http2jptest 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.
ServerConnectionhandles client prefaces, response headers, server pushes, Alt-Svc, and ORIGIN. Meanwhile,ClientConnectionmanages 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
ServerConfigurationandClientConfigurationusing fluentwith*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 standardWriteHandleInterfacewith aflush()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.Release notes
Open source →features
- feat(io): introduce
Psl\IO\BufferedWriteHandleInterface, extendingWriteHandleInterfacewithflush()for handles that buffer data internally before writing to an underlying resource - feat: introduce
Compressioncomponent with streaming compression/decompression abstractions for IO handles. ProvidesCompressorInterface,DecompressorInterface, four handle decorators (CompressingReadHandle,CompressingWriteHandle,DecompressingReadHandle,DecompressingWriteHandle), and convenience functionscompress()anddecompress() - feat: introduce
HPACKcomponent - RFC 7541 HPACK header compression for HTTP/2 - feat: introduce
H2component - HTTP/2 binary framing protocol implementation - feat: introduce
Cachecomponent - async-safe in-memory LRU cache with per-key atomicity viaKeyedSequence, proactive TTL expiration via event loop
-
6.0.318 Mar 2026Release notes
Open source →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.
-
6.0.218 Mar 2026Release notes
Open source →PSL 6.0.2
Patch release fixing a bug in
IO\Readerthat affected non-blocking stream reads (TLS, TCP, etc.).Bug fixes
IO: Reader no longer treats empty non-blocking reads as EOF
Reader::readUntil()andReader::readUntilBounded()assumed that an emptyread()meant end-of-stream. On non-blocking handles (TLS, TCP, Unix sockets),read()can return empty before data arrives. This causedreadLine()to return the entire stream content as a single string instead of splitting into individual lines.This bug affected any code using
IO\Readerwith network streams. If you were usingreadLine(),readUntil(), orreadUntilBounded()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 topackages/default/src/Psl/Default/instead of the non-existent top-levelsrc/Psl/Default/.Full changelog
See CHANGELOG.md for details.
-
6.0.118 Mar 2026Release notes
Open source →- fix(io):
Reader::readUntil()andReader::readUntilBounded()no longer treat empty reads from non-blocking streams as EOF, fixingreadLine()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-levelsrc/Psl/path - internal: add
splitter auditcommand to verify organization repository settings (wiki, issues, discussions, PRs, tag immutability).
- fix(io):
-
6.0.017 Mar 2026Release notes
Open source →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:
- Repository: github.com/php-standard-library/php-standard-library (was
azjezz/psl) - Website: php-standard-library.dev (was
psl.carthage.software) - Packagist:
php-standard-library/php-standard-library(wasazjezz/psl)
The
azjezz/pslpackage is now abandoned. Runcomposer require php-standard-library/php-standard-libraryto switch.The namespace has not changed. It is
Psl\, and it will always remainPsl\.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/typeBuilding an async TCP server?
composer require php-standard-library/tcpWorking with URIs?
composer require php-standard-library/uriEvery 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 $timeoutpattern across all async/IO operations:CancellationTokenInterface- base contractTimeoutCancellationToken- auto-cancels after a durationSignalCancellationToken- manually triggered cancellationLinkedCancellationToken- cancelled when either of two inner tokens fires
More highlights
TaskGroupandWaitGroupfor structured concurrencyQuotedPrintableandEncodedWordencoding (RFC 2045, RFC 2047)- Streaming Base64/Hex/QuotedPrintable IO handles
TLS\Listenerfor wrapping any listener with TLSTCP\RestrictedListenerfor IP/CIDR-based access controlNetwork\CompositeListenerfor accepting from multiple listenersBufferedReadHandleInterfacewithreadByte(),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 $timeoutparameters are nowCancellationTokenInterface $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(), andSocks\Connectornow accept configuration objects instead of individual parameters.Removed timeout exceptions.
IO\Exception\TimeoutException,Network\Exception\TimeoutException,Process\Exception\TimeoutException, andShell\Exception\TimeoutExceptionare removed. UseAsync\Exception\CancelledExceptioninstead.TLS renamed.
TLS\ServerConfig->TLS\ServerConfiguration,TLS\ClientConfig->TLS\ClientConfiguration.See the full CHANGELOG for the complete list.
Bug fixes
RetryConnectorbackoff sleep now respects cancellation tokensIO\write(),IO\write_line(),IO\write_error(),IO\write_error_line(), andStr\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.
Release notes
Open source →breaking changes
- BC - All
null|Duration $timeoutparameters across IO, Network, TCP, TLS, Unix, UDP, Socks, Process, and Shell components have been replaced withCancellationTokenInterface $cancellation = new NullCancellationToken(). This enables both timeout-based and signal-based cancellation of async operations. - BC - Removed
Psl\IO\Exception\TimeoutException- usePsl\Async\Exception\CancelledExceptioninstead. - BC - Removed
Psl\Network\Exception\TimeoutException- usePsl\Async\Exception\CancelledExceptioninstead. - BC - Removed
Psl\Process\Exception\TimeoutException- usePsl\Async\Exception\CancelledExceptioninstead. - BC - Removed
Psl\Shell\Exception\TimeoutException- usePsl\Async\Exception\CancelledExceptioninstead. - BC -
Psl\IO\CloseHandleInterfacenow requires anisClosed(): boolmethod. - BC -
Network\SocketInterface::getLocalAddress()andNetwork\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 ofPHP_EOL. Trailing"\r"is stripped, so both"\n"and"\r\n"line endings are handled consistently across all platforms. UsereadUntil(PHP_EOL)for system-dependent behavior. - BC -
Psl\TLS\ServerConfigrenamed toPsl\TLS\ServerConfiguration. - BC -
Psl\TLS\ClientConfigrenamed toPsl\TLS\ClientConfiguration. - BC - All variables and parameters across the codebase now use
$camelCasenaming 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()andUnix\Socket::listen()now acceptUnix\ListenConfigurationinstead of individual parameters. - BC -
UDP\Socket::bind()now acceptsUDP\BindConfigurationinstead of individual parameters. - BC -
TCP\Socketsetter/getter methods (setReuseAddress,setReusePort,setNoDelay, etc.) have been removed. Use configuration objects instead. - BC -
TCP\Connectorconstructor now acceptsTCP\ConnectConfigurationinstead ofbool $noDelay. - BC -
Socks\Connectorconstructor changed from(string $proxyHost, int $proxyPort, ?string $username, ?string $password, ConnectorInterface $connector)to(ConnectorInterface $connector, Socks\Configuration $configuration). - BC - Renamed
ingoingtoongoingacrossSemaphore,Sequence,KeyedSemaphore, andKeyedSequence(hasIngoingOperations()->hasOngoingOperations(),getIngoingOperations()->getOngoingOperations(), etc.).
features
- feat(async): introduce
Psl\Async\CancellationTokenInterfacefor 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 viacancel(?Throwable $cause) - feat(async): introduce
Psl\Async\TimeoutCancellationToken- auto-cancels after aDuration, replacing the oldDuration $timeoutpattern - 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 optionalCancellationTokenInterfaceparameter, allowing early wake-up on cancellation - feat(async):
Awaitable::await()now accepts an optionalCancellationTokenInterfaceparameter - feat(async):
Sequence::waitFor()andSequence::waitForPending()now accept an optionalCancellationTokenInterfaceparameter - feat(async):
Semaphore::waitFor()andSemaphore::waitForPending()now accept an optionalCancellationTokenInterfaceparameter - feat(async):
KeyedSequence::waitFor()andKeyedSequence::waitForPending()now accept an optionalCancellationTokenInterfaceparameter - feat(async):
KeyedSemaphore::waitFor()andKeyedSemaphore::waitForPending()now accept an optionalCancellationTokenInterfaceparameter - feat(channel):
SenderInterface::send()andReceiverInterface::receive()now accept an optionalCancellationTokenInterfaceparameter - feat(network):
ListenerInterface::accept()now accepts an optionalCancellationTokenInterfaceparameter - feat(tcp):
TCP\ListenerInterface::accept()now accepts an optionalCancellationTokenInterfaceparameter - feat(unix):
Unix\ListenerInterface::accept()now accepts an optionalCancellationTokenInterfaceparameter - feat(tls):
TLS\Acceptor::accept(),TLS\LazyAcceptor::accept(),TLS\ClientHello::complete(), andTLS\Connector::connect()now accept an optionalCancellationTokenInterfaceparameter - cancellation propagates through the TLS handshake - feat(tls):
TLS\TCPConnector::connect()andTLS\connect()now pass the cancellation token through to the TLS handshake - feat(async): introduce
Psl\Async\TaskGroupfor running closures concurrently and awaiting them all withdefer()+awaitAll() - feat(async): introduce
Psl\Async\WaitGroup, a counter-based synchronization primitive withadd(),done(), andwait() - feat(encoding): introduce
Psl\Encoding\QuotedPrintable\encode(),decode(), andencode_line()for RFC 2045 quoted-printable encoding with configurable line length and line ending - feat(encoding): introduce
Psl\Encoding\EncodedWord\encode()anddecode()for RFC 2047 encoded-word encoding/decoding in MIME headers (B-encoding and Q-encoding with automatic selection) - feat(tls): introduce
TLS\ListenerInterfaceandTLS\Listener, wrapping anyNetwork\ListenerInterfaceto perform TLS handshakes on accepted connections - feat(encoding): add
Base64\Variant::Mimefor 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), bridgingPsl\IOandPsl\Encodingfor transparent encode/decode on read/write - feat(io): introduce
Psl\IO\BufferedReadHandleInterface, extendingReadHandleInterfacewithreadByte(),readLine(),readUntil(), andreadUntilBounded() - feat(io):
Psl\IO\Readernow implementsBufferedReadHandleInterface - feat(tcp): introduce
TCP\ListenConfigurationandTCP\ConnectConfigurationwith immutablewith*builder methods - feat(unix): introduce
Unix\ListenConfigurationwith immutablewith*builder methods - feat(udp): introduce
UDP\BindConfigurationwith immutablewith*builder methods - feat(socks): introduce
Socks\Configurationwith immutablewith*builder methods for proxy host, port, and credentials - feat(tcp): introduce
TCP\RestrictedListener, wrapping a listener to restrict connections to a set of allowedIP\AddressandCIDR\Blockentries - feat(network): introduce
Network\CompositeListener, accepting connections from multiple listeners concurrently through a singleaccept()call - feat: introduce
URIcomponent - 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
IRIcomponent - 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
URLcomponent - strict URL type with scheme and authority validation, default port stripping for known schemes, and URI/IRI conversion - feat: introduce
Punycodecomponent - RFC 3492 Punycode encoding and decoding for internationalized domain names - fix(tcp):
RetryConnectorbackoff 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(), andStr\format()no longer pass the message throughsprintf/vsprintfwhen no arguments are given, preventing format string errors when the message contains%characters
migration guide
Replace
Durationtimeout parameters withTimeoutCancellationToken:// 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(); - Repository: github.com/php-standard-library/php-standard-library (was
-
5.5.012 Mar 2026Release notes
Open source →PSL 5.5.0
IO: Bounded Reads
Reader::readUntilBounded()reads from a handle until a suffix is found, just likereadUntil(), but enforces a maximum byte limit. If the suffix is not encountered within$max_bytes, anIO\Exception\OverflowExceptionis 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()andType\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): matchesnull, 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
Release notes
Open source →features
- feat(io): added
Reader::readUntilBounded(string $suffix, int $max_bytes, ?Duration $timeout)method, which reads until a suffix is found, but throwsIO\Exception\OverflowExceptionif the content exceeds$max_bytesbefore the suffix is encountered - #620 - by @azjezz - feat(io): added
IO\Exception\OverflowExceptionexception 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
-
-
5.4.010 Mar 2026Release notes
Open source →features
- feat(dict, vec): add filter_nonnull_by and map_nonnull - #576 by @Dima-369
- feat(tcp): add
backlogparameter toTCP\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
-
5.3.008 Mar 2026Release notes
Open source →features
- feat(io): introduce
IO\spool()for memory-backed handles that spill to disk
- feat(io): introduce
-
5.2.007 Mar 2026Release notes
Open source →features
- feat: introduce
IPcomponent with immutable, binary-backedAddressvalue object andFamilyenum - feat(cidr):
CIDR\Block::contains()now acceptsstring|IP\Address
- feat: introduce
-
5.1.005 Mar 2026Release notes
Open source →features
- feat(tls): introduce
TLS\TCPConnectorfor poolable TLS connections - feat(tls):
TLS\StreamInterfacenow extendsTCP\StreamInterface, enabling TLS streams to be used withTCP\SocketPoolInterface
- feat(tls): introduce
-
5.0.004 Mar 2026Release notes
Open source →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\Shellinternals refactored; dead code removed - #596 by @azjezzPsl\Env\temp_dir()now always returns a canonicalized path - #599 by @azjezz
features
- feat: introduce
Ansicomponent - #588 by @azjezz - feat: introduce
Terminalcomponent - #589 by @azjezz - feat: introduce
Processcomponent - #578 by @azjezz - feat: introduce
Binarycomponent - #598 by @azjezz - feat: introduce
Interoperabilitycomponent - #582 by @azjezz - feat: introduce
TLScomponent - #585 by @azjezz - feat: introduce
UDPcomponent - #585 by @azjezz - feat: introduce
CIDRcomponent - #585 by @azjezz - feat: introduce
Sockscomponent - #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()andIO\copy_bidirectional()- #585 by @azjezz - feat(vec): add
Vec\flatten()- #583 by @azjezz - feat: introduce
Cryptocomponent 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
-
4.3.024 Feb 2026 -
4.2.129 Jan 2026 -
4.2.025 Oct 2025 -
4.1.023 Oct 2025Release notes
Open source →features
- feat: add
Graphcomponent with directed and undirected graph support - #547 by @azjezz - feat: add
Treecomponent for hierarchical data structures - #546 by @azjezz - feat(type): add reflection-based type functions for class members - #543 by @azjezz
other
- chore: migrate from
maketojust- #544 by @azjezz
- feat: add
-
4.0.109 Oct 2025Release notes
Open source →fixes, and improvements
- refactor: remove redundant
@vartags from constants - #533 by @azjezz
- refactor: remove redundant
-
4.0.015 Sep 2025Release notes
Open source →breaking changes
Psl\Result\wrap()no longer unwraps nested results - #531 by @azjezzPsl\Collection\Map,Psl\Collection\MutableMap,Psl\Collection\Set, andPsl\Collection\MutableSetnow have a more natural JSON serialization - #512 by @josh-rai- A large number of intersection interfaces in the
Psl\IOandPsl\Filenamespaces 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
containertype - #513 by @azjezz - feat(type): add
int_rangetype - #510 by @george-steel - feat(type): add
always_asserttype - #522 by @azjezz - feat(iter): add
search_with_keys_optandsearch_with_keysfunctions - #490 by @simon-podlipsky
fixes, and improvements
- refactor: improve type inference for non-empty lists - #529 by @azjezz
- refactor: improve type inference for
IterandRegex- #528 by @azjezz
other
-
3.3.003 Mar 2025Nothing published for this version
-
3.2.023 Jan 2025Nothing published for this version
-
3.1.021 Nov 2024Nothing published for this version
-
3.0.213 Sep 2024Nothing published for this version
-
3.0.112 Sep 2024Nothing published for this version
-
3.0.003 Sep 2024Nothing published for this version
-
2.9.105 Apr 2024Nothing published for this version
-
2.9.029 Dec 2023Nothing published for this version
-
2.8.022 Nov 2023Nothing published for this version
-
2.7.019 Jul 2023Release notes
Open source →features
- feat(encoding): introduce
Base64\Variantenum to support encoding/decoding different variants - #408 by @Gashmob
fixes, and improvements
- feat(encoding): introduce
-
2.6.018 May 2023 -
2.5.017 Mar 2023Release notes
Open source →features
- feat(result): introduce
Result\try_catchfunction - #403 by @azjezz
fixes, and improvements
- fix(file): improve consistency when creating files for write-mode - #401 by @veewee
- feat(result): introduce
-
2.4.126 Jan 2023Release notes
Open source →fixes, and improvements
- fix(type): un-deprecate
Psl\Type\positive_intfunction - #400 by @dragosprotung
- fix(type): un-deprecate
-
2.4.024 Jan 2023Release notes
Open source →features
- feat(range): introduced
Psl\Rangecomponent - #378 by @azjezz - feat(str): introduced
Psl\Str\range,Psl\Str\Byte\range, andPsl\Str\Grapheme\rangefunctions - #385 by @azjezz - feat(type): introduced
Psl\Type\uintfunction - #393 by @azjezz - feat(type): introduced
Psl\Type\i8,Psl\Type\i16,Psl\Type\i32,Psl\Type\i64functions - #392 by @azjezz - feat(type): introduced
Psl\Type\u8,Psl\Type\u16,Psl\Type\u32functions - #395 by @KennedyTedesco - feat(type): introduced
Psl\Type\f32, andPsl\Type\f64functions - #396 by @KennedyTedesco - feat(type): introduced
Psl\Type\nonnullfunction - #392 by @azjezz - feat(option): improve options type declarations and add
andThenmethod - #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_intfunction, usePsl\Type\uintinstead - by @azjezz
- feat(range): introduced
-
2.3.120 Dec 2022Release notes
Open source →fixes, and improvements
- fix(vec):
Vec\reproduceandVec\rangereturn type is always non-empty-list - #383 by @dragosprotung
other
- chore: update license copyright year - #371 by @azjezz
- fix(vec):
-
2.3.001 Dec 2022 -
2.2.026 Nov 2022 -
2.1.004 Nov 2022Release notes
Open source →features
- introduced a new
Psl\Type\unit_enumfunction - @19d1230 by @azjezz - introduced a new
Psl\Type\backed_enumfunction - @19d1230 by @azjezz - introduced a new
Psl\Type\mixed_vecfunction - #362 by @BackEndTea - introduced a new
Psl\Type\mixed_dictfunction - #362 by @BackEndTea
fixes, and improvements
- improved
Psl\Type\vecperformance - #364 by @BackEndTea - improved
Psl\Type\float, andPsl\Type\num- #367 by @bcremer
other
- introduced a new
-
2.0.410 Oct 2022Nothing published for this version
-
2.0.307 Jun 2022Nothing published for this version
-
2.0.230 May 2022Nothing published for this version
-
2.0.111 May 2022Nothing published for this version
-
2.0.007 May 2022Release notes
Open source →-
BC - removed
Psl\Arrcomponent. -
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, andPsl\Type\is_stringfunctions ( useTypeInterface::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, andPsl\Iter\zipfunctions. -
BC - signature of
Psl\Iter\reduce_keysfunction changed fromreduce_keys<Tk, Tv, Ts>(iterable<Tk, Tv> $iterable, (callable(?Ts, Tk): Ts) $function, Ts|null $initial = null): Ts|nulltoreduce_keys<Tk, Tv, Ts>(iterable<Tk, Tv> $iterable, (callable(Ts, Tk): Ts) $function, Ts $initial): Ts. -
BC - signature of
Psl\Iter\reduce_with_keysfunction changed fromreduce_with_keys<Tk, Tv, Ts>(iterable<Tk, Tv> $iterable, (callable(?Ts, Tk, Tv): Ts) $function, Ts|null $initial = null): Ts|nulltoreduce_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, usephp-standard-library/psalm-pluginpackage instead. -
dropped support for PHP 8.0
-
BC - signature of
Psl\Type\objectfunction changed fromobject<T of object>(classname<T> $classname): TypeInterface<T>toobject(): TypeInterface<object>( to preserve the old behavior, usePsl\Type\instance_of) -
introduced
Psl\Type\instance_offunction, with the signature ofinstance_of<T of object>(classname<T> $classname): TypeInterface<T>. -
introduced a new
Psl\Asynccomponent. -
refactored
Psl\IOhandles API. -
introduced a new
Psl\Filecomponent. -
refactor
Psl\Shell\executeto usePsl\IOcomponent. -
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 -
$encodingargument forPsl\Strfunctions now acceptsPsl\Str\Encodinginstead of?string. -
introduced a new
Psl\Runtimecomponent. -
introduced a new
Psl\Networkcomponent. -
introduced a new
Psl\TCPcomponent. -
introduced a new
Psl\Unixcomponent. -
introduced a new
Psl\Channelcomponent. -
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\Encodingenum. -
BC -
$encodingargument forPsl\Htmlfunctions now acceptsPsl\Html\Encodinginstead of?string. -
BC -
Psl\Shell\escape_commandfunction has been removed, no replacement is available. -
introduced a new
Psl\Math\acosfunction. -
introduced a new
Psl\Math\asinfunction. -
introduced a new
Psl\Math\atanfunction. -
introduced a new
Psl\Math\atan2function. -
BC - The type of the $numbers argument of
Psl\Math\meanhas changed tolist<int|float>instead ofiterable<int|float>. -
BC - The type of the $numbers argument of
Psl\Math\medianhas changed tolist<int|float>instead ofiterable<int|float>. -
introduced a new
Psl\Promisecomponent. -
BC -
Psl\Result\ResultInterfacenow implementsPsl\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, andPsl\Str\Graphemefunctions now throwPsl\Str\Exception\OutOfBoundsExceptioninstead ofPsl\Exception\InvaraintViolationsExceptionwhen$offsetis out-of-bounds. -
BC -
Psl\Collection\IndexAccessInterface::at()now throwPsl\Collection\Exception\OutOfBoundsExceptioninstead ofPsl\Exception\InvariantViolationExceptionif$kis out-of-bounds. -
BC -
Psl\Collection\AccessibleCollectionInterface::slicesignature has changed fromslice(int $start, int $length): statictoslice(int $start, ?int $length = null): static -
BC - All psl functions previously accepting
callable, now accept onlyClosure. -
BC -
Psl\DataStructure\QueueInterface::dequeue, andPsl\DataStructure\StackInterface::popnow throwPsl\DataStructure\Exception\UnderflowExceptioninstead ofPsl\Exception\InvariantViolationExceptionwhen the data structure is empty. -
BC -
Psl\Filesystem\write_file($file, $content)function has been removed, usePsl\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, usePsl\File\read($file, $offset, $length)instead. -
BC -
Psl\Filesystem\append_file($file, $contents)function has been removed, usePsl\File\write($file, $contents, File\WriteMode::APPEND)instead. -
BC -
Psl\Filesystemfunctions no longer throwPsl\Exception\InvariantViolationException.New exceptions:
Psl\Filesystem\Exception\NotReadableExceptionthrown when attempting to read from a non-readable nodePsl\Filesystem\Exception\NotFileExceptionthrown when attempting a file operation on a non-file node.Psl\Filesystem\Exception\NotDirectoryExceptionthrown when attempting a directory operation on a non-directory node.Psl\Filesystem\Exception\NotSymbolicLinkExceptionthrown when attempting a symbolic link operation on a non-symbolic link node.Psl\Filesystem\Exception\NotFoundExceptionthrown when attempting an operation on a non-existing node.
-
introduced
Psl\Hash\Algorithmenum. -
introduced
Psl\Hash\Hmac\Algorithmenum. -
BC -
Psl\Hash\hash, andPsl\Hash\Context::forAlgorithmnow takePsl\Hash\Algorithmas an algorithm, rather than a string. -
BC -
Psl\Hash\Hmac\hash, andPsl\Hash\Context::hmacnow takePsl\Hash\Hmac\Algorithmas an algorithm, rather than a string. -
BC - A new method
chunk(positive-int $size): CollectionInterfacehas been added toPsl\Collection\CollectionInterface. -
introduced a new
Psl\OScomponent. -
introduced
Psl\Password\Algorithmenum -
BC - all constants of
Psl\Passwordcomponent has been removed. -
BC - function
Psl\Password\algorithms()have been removed. -
BC -
Psl\Result\ResultInterface::getException()method has been renamed toPsl\Result\ResultInterface::getThrowable() -
BC -
Psl\Result\wrapfunction now catches allThrowables instead of onlyExceptions -
introduced a new
Psl\Result\reflectfunction -
BC -
Psl\Shell\escape_argumentfunction has been removed,Shell\executearguments are now always escaped. -
BC -
$escape_argumentsargument ofShell\executefunction has been removed. -
introduced a new
Psl\Shell\ErrorOutputBehaviorenum -
added a new
$error_output_behaviorargument toShell\executefunction, which can be used to return the command error output content, as well as the standard output content. -
introduced a new
Psl\Shell\unpackfunction to unpack packed result ofShell\execute( seePsl\Shell\ErrorOutputBehavior::Packed). -
introduced a new
Psl\Shell\stream_unpackfunction to unpack packed result ofShell\executechunk by chunk, maintaing order ( seePsl\Shell\ErrorOutputBehavior::Packed).
-
-
2.0.0-rc215 Jan 2022 pre-releaseNothing published for this version
-
2.0.0-rc108 Jan 2022 pre-releaseNothing published for this version
-
1.9.310 Dec 2021Nothing published for this version
-
1.9.210 Nov 2021Nothing published for this version
-
1.9.106 Nov 2021Nothing published for this version
-
1.9.018 Oct 2021Nothing published for this version
-
1.8.208 Dec 2021Nothing published for this version
-
1.8.103 Oct 2021Nothing published for this version
-
1.8.012 Aug 2021Nothing published for this version
-
1.7.408 Dec 2021Nothing published for this version
-
1.7.325 Aug 2021Nothing published for this version
-
1.7.224 May 2021Nothing published for this version
-
1.7.119 May 2021Nothing published for this version
-
1.7.015 May 2021Nothing published for this version
-
1.6.323 Feb 2022Nothing published for this version
-
1.6.208 Dec 2021Nothing published for this version