Releases: matasarei/php-tcp
Release list
1.3.1
Fixed
-
A read timeout was reported as a broken connection on PHP 8.1 and newer.
fread()returns
falsethere where earlier versions returned an empty string, and the client took that for a
dead stream — so the default framing mode, which ends a response on a quiet interval, threw
ConnectionException: Request failed, broken connection.on every request against a real
socket. A timeout is now told apart from a broken stream by
stream_get_meta_data()['timed_out'].Present since 1.0 and dormant until PHP 8.1 changed the return value. The suite missed it
because it drives the client through aphp://stream wrapper, whose read cannot return
false; a socket-pair test now covers the real thing.
1.3.0
Added
Client::setMaxResponseSize()andClient::DEFAULT_MAX_RESPONSE_SIZE— a response is now
capped at 8 MiB by default and throws aRequestExceptionbeyond it. Passnullfor the
previous unlimited behaviour.StreamSocketandFSockettake a second constructor argument,$blocking. The first
argument now only sets the read timeout; previously it decided both, so a positive timeout
forced a blocking stream. Defaults keep the old behaviour.
Fixed
- Security: neither transport pinned a scheme, so a host such as
udp://127.0.0.1opened a
UDP socket.StreamSocketandFSocketnow build atcp://address and reject a host
containing://with aSocketException. - Security: the read timeout was only checked when a read came back empty, so a peer that
kept sending was never timed out and the response grew until the process ran out of memory.
The elapsed time is now checked on every iteration. - The debug log carried the whole
Requestobject, putting the request body — credentials
included — into the consumer's log. It now carries the body length. Client::connect()accepts afloattimeout. It had no parameter type and passed the value
to anintparameter, soconnect(0.5)became0and raised an implicit-conversion
deprecation on PHP 8.1+.- A read no longer takes twice the timeout: the clock started after the initial wait had already
returned, so the wait and the read loop each got a full one. The remaining overshoot is the
socket's own read timeout, since the elapsed check sits before a blockingfread(). phpunit.xmlno longer setsstopOnFailure, so a failing run reports every failure.
Changed
- Package renamed from
matasarei/phptcptomatasarei/php-tcp, and the repository renamed to
match — install withcomposer require matasarei/php-tcp. The PHP namespaceMatasar\PhpTcp
is unchanged, so no code changes are required. Packagist serves the whole tag history under the
new name, so 1.0, 1.1 and 1.2.0 resolve there too, even though their owncomposer.jsonstill
carries the old one. - The no-response exception message is now
Request timeout, no response.— it previously
carried a stray backslash. Code matching on that string needs updating. StreamSocketandFSockettype their first constructor argument asint; a value that is
not an integer now raises aTypeErrorinstead of being coerced. Same for
Client::connect(), which is nowfloatand no longer acceptsnull.
1.2.0
Robustness fixes for the stream handling, opt-in delimiter-based response framing, and modernized tooling.
Added
Client::setDelimiter()— optional end-of-response marker (e.g."\n"for line-based protocols such as JSON-RPC over TCP). With a delimiter set, a response is complete as soon as it ends with the delimiter instead of after a silent interval on the stream: reads return sooner and truncated responses are detected (RequestExceptionon timeout,ConnectionExceptionwhen the connection closes before the response is completed) rather than silently accepted.Client::setPollInterval()andClient::DEFAULT_POLL_INTERVAL— renamed from "connection lag": the value is the pause between data availability checks.- CI: GitHub Actions matrix testing PHP 7.4, 8.0, 8.1, 8.2, 8.3, 8.4 and 8.5.
Fixed
- Infinite loop on a broken stream:
read()looped onfread() !== '', butfread()returnsfalseon error, so a broken stream spun forever. It now throws aConnectionException. - A connection closed by the peer looked like a timeout: neither read loop checked
feof(), so a closed connection kept polling for the full request timeout (30 s by default) and then reported a timeout. It now fails fast withConnectionException. - Unchecked and partial writes:
request()ignored thefwrite()result, so large request bodies could be partially written with no error surfaced. Writes now continue until the whole body is sent; a zero-byte write (full send buffer in non-blocking mode) is retried until the request timeout.
Changed
- Default chunk size raised from 1024 to 8192 bytes to match the size of PHP's internal stream read buffer.
psr/logv1, v2 and v3 are now accepted (Client::setLogger()returnsvoidper the v3 interface).- Minimum PHP version raised from 7.1 to 7.4.
- Test suite migrated from PHPUnit 7 to PHPUnit 9.6; README rewritten.
Deprecated
Client::setConnectionLag()— usesetPollInterval()instead.Client::DEFAULT_CONNECTION_LAG— useDEFAULT_POLL_INTERVALinstead.
Removed
- Unused
ext-jsonrequirement fromcomposer.json.
Backward-compatibility notes
- Wire behaviour without a delimiter is unchanged.
- A peer-closed connection now throws
ConnectionExceptionpromptly instead ofRequestExceptionafter the full timeout — code that caught onlyRequestExceptionfor that case should also catchConnectionException.
Full Changelog: 1.1...1.2.0