Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ PHP NEWS
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
?? ??? ????, PHP 8.6.0beta3

- Core:
. Calling is_a() or is_subclass_of() with a string as the first argument
when $allow_string is false is now deprecated. (Daniel Scherzer)

- CLI:
. Fixed bug GH-23242 (PHP development server does not support Expect
100-continue flow control). (Sjoerd Langkemper)
Expand Down Expand Up @@ -80,6 +84,10 @@ PHP NEWS
. Fixed writing to a dimension of the object returned by attributes() not
creating the attribute. (Ilia Alshanetsky)

- Streams:
. Added so_rcvbuf and so_sndbuf stream socket context options, setting the
socket receive and send buffer sizes in bytes. (David Carlier)


27 Aug 2026, PHP 8.6.0beta2

Expand Down
11 changes: 11 additions & 0 deletions UPGRADING
Original file line number Diff line number Diff line change
Expand Up @@ -486,6 +486,13 @@ PHP 8.6 UPGRADE NOTES
sockets. A positive value enables lingering for that many seconds, zero
or a negative value disables it. Values above 65535 are clamped as the
linger time is limited to an unsigned short on some platforms.
. Added stream socket context options so_rcvbuf and so_sndbuf that set the
socket receive and send buffer sizes in bytes (SO_RCVBUF and SO_SNDBUF) on
TCP and UDP sockets. The value must be an integer between 1 and 2147483647,
any other value makes the stream creation fail. The operating system may
round, cap or otherwise adjust the requested size, and may stop sizing that
buffer automatically, so the size read back can differ from the one
requested.
. Allowed casting filtered streams as file descriptors for select.
. Added the "write_seek_mode" filter parameter for the bz2, iconv,
zlib, and string stream filters. This parameter must be set via an
Expand Down Expand Up @@ -529,6 +536,10 @@ PHP 8.6 UPGRADE NOTES
RFC: https://wiki.php.net/rfc/deprecations_php_8_6#deprecate_the_possibility_to_name_a_function_readonly
. Passing a 3rd argument to define() is now deprecated.
RFC: https://wiki.php.net/rfc/deprecations_php_8_6#deprecate_define_with_case_insensitive_being_specified
. Calling is_a() or is_subclass_of() with a string as the first argument
when $allow_string is false is now deprecated.
RFC: https://wiki.php.net/rfc/deprecations_php_8_6#deprecate_is_a_with_string_when_allow_string_is_false
RFC: https://wiki.php.net/rfc/deprecations_php_8_6#deprecate_is_subclass_of_with_string_when_allow_string_is_false

- BZ2:
. Passing an object for the Bzip2 {de}compression stream filter is now
Expand Down
12 changes: 10 additions & 2 deletions ext/standard/basic_functions.stub.php
Original file line number Diff line number Diff line change
Expand Up @@ -2331,13 +2331,21 @@ function strcoll(string $string1, string $string2): int {}
*/
function trim(string $string, string $characters = " \f\n\r\t\v\0"): string {}

/** @compile-time-eval */
/**
* @compile-time-eval
* @frameless-function {"arity": 1}
* @frameless-function {"arity": 2}
*/
function rtrim(string $string, string $characters = " \f\n\r\t\v\0"): string {}

/** @alias rtrim */
function chop(string $string, string $characters = " \f\n\r\t\v\0"): string {}

/** @compile-time-eval */
/**
* @compile-time-eval
* @frameless-function {"arity": 1}
* @frameless-function {"arity": 2}
*/
function ltrim(string $string, string $characters = " \f\n\r\t\v\0"): string {}

/**
Expand Down
22 changes: 19 additions & 3 deletions ext/standard/basic_functions_arginfo.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions ext/standard/basic_functions_decl.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

56 changes: 56 additions & 0 deletions ext/standard/string.c
Original file line number Diff line number Diff line change
Expand Up @@ -651,13 +651,69 @@ PHP_FUNCTION(rtrim)
}
/* }}} */

ZEND_FRAMELESS_FUNCTION(rtrim, 1)
{
zval str_tmp;
zend_string *str;

Z_FLF_PARAM_STR(1, str, str_tmp);

ZVAL_STR(return_value, php_trim_int(str, /* what */ NULL, /* what_len */ 0, /* mode */ 2));

flf_clean:
Z_FLF_PARAM_FREE_STR(1, str_tmp);
}

ZEND_FRAMELESS_FUNCTION(rtrim, 2)
{
zval str_tmp, what_tmp;
zend_string *str, *what;

Z_FLF_PARAM_STR(1, str, str_tmp);
Z_FLF_PARAM_STR(2, what, what_tmp);

ZVAL_STR(return_value, php_trim_int(str, ZSTR_VAL(what), ZSTR_LEN(what), /* mode */ 2));

flf_clean:
Z_FLF_PARAM_FREE_STR(1, str_tmp);
Z_FLF_PARAM_FREE_STR(2, what_tmp);
}

/* {{{ Strips whitespace from the beginning of a string */
PHP_FUNCTION(ltrim)
{
php_do_trim(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
}
/* }}} */

ZEND_FRAMELESS_FUNCTION(ltrim, 1)
{
zval str_tmp;
zend_string *str;

Z_FLF_PARAM_STR(1, str, str_tmp);

ZVAL_STR(return_value, php_trim_int(str, /* what */ NULL, /* what_len */ 0, /* mode */ 1));

flf_clean:
Z_FLF_PARAM_FREE_STR(1, str_tmp);
}

ZEND_FRAMELESS_FUNCTION(ltrim, 2)
{
zval str_tmp, what_tmp;
zend_string *str, *what;

Z_FLF_PARAM_STR(1, str, str_tmp);
Z_FLF_PARAM_STR(2, what, what_tmp);

ZVAL_STR(return_value, php_trim_int(str, ZSTR_VAL(what), ZSTR_LEN(what), /* mode */ 1));

flf_clean:
Z_FLF_PARAM_FREE_STR(1, str_tmp);
Z_FLF_PARAM_FREE_STR(2, what_tmp);
}

/* {{{ Wraps buffer to selected number of characters using string break char */
PHP_FUNCTION(wordwrap)
{
Expand Down
94 changes: 94 additions & 0 deletions ext/standard/tests/network/so_rcvbuf_sndbuf.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
--TEST--
stream_socket_server() and stream_socket_client() SO_RCVBUF and SO_SNDBUF context options test
--EXTENSIONS--
sockets
--FILE--
<?php
function buffers($stream): array {
$sock = socket_import_stream($stream);
return [
socket_get_option($sock, SOL_SOCKET, SO_RCVBUF),
socket_get_option($sock, SOL_SOCKET, SO_SNDBUF),
];
}

// Shrinking is always honoured, while growing may be capped by the system maximum.
function context(int $rcvbuf, int $sndbuf) {
return stream_context_create(['socket' => [
'so_rcvbuf' => intdiv($rcvbuf, 4),
'so_sndbuf' => intdiv($sndbuf, 4),
]]);
}

function port($server): int {
return (int)substr(strrchr(stream_socket_get_name($server, false), ':'), 1);
}

$control = stream_socket_server("tcp://127.0.0.1:0", $errno, $errstr,
STREAM_SERVER_BIND | STREAM_SERVER_LISTEN);

if (!$control) {
die('Unable to create server');
}

[$rcvbuf, $sndbuf] = buffers($control);

$server = stream_socket_server("tcp://127.0.0.1:0", $errno, $errstr,
STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, context($rcvbuf, $sndbuf));

if (!$server) {
die('Unable to create server');
}

echo "Listen buffers\n";
[$listen_rcvbuf, $listen_sndbuf] = buffers($server);
var_dump($listen_rcvbuf < $rcvbuf);
var_dump($listen_sndbuf < $sndbuf);

// A connection is compared against another connection: some systems size the
// receive buffer of a connected socket on their own.
$control_client = stream_socket_client("tcp://127.0.0.1:" . port($server), $errno, $errstr, 30);

if (!$control_client) {
die('Unable to create client');
}

$control_accepted = stream_socket_accept($server, 1);

if (!$control_accepted) {
die('Unable to accept connection');
}

[, $client_sndbuf] = buffers($control_client);

$client = stream_socket_client("tcp://127.0.0.1:" . port($server), $errno, $errstr, 30,
STREAM_CLIENT_CONNECT, context($client_sndbuf, $client_sndbuf));

if (!$client) {
die('Unable to create client');
}

$accepted = stream_socket_accept($server, 1);

if (!$accepted) {
die('Unable to accept connection');
}

echo "Client buffers\n";
[, $client_sndbuf2] = buffers($client);
var_dump($client_sndbuf2 < $client_sndbuf);

fclose($accepted);
fclose($control_accepted);
fclose($client);
fclose($control_client);
fclose($server);
fclose($control);

?>
--EXPECT--
Listen buffers
bool(true)
bool(true)
Client buffers
bool(true)
34 changes: 34 additions & 0 deletions ext/standard/tests/network/so_rcvbuf_sndbuf_error.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
--TEST--
SO_RCVBUF and SO_SNDBUF context options reject invalid values
--FILE--
<?php
foreach (['so_rcvbuf', 'so_sndbuf'] as $option) {
foreach ([0, -1, 'abc'] as $value) {
$context = stream_context_create(['socket' => [$option => $value]]);
var_dump(@stream_socket_server("tcp://127.0.0.1:0", $errno, $errstr,
STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $context));
echo $errstr, PHP_EOL;
}
}

$context = stream_context_create(['socket' => ['so_rcvbuf' => 0]]);
var_dump(@stream_socket_client("tcp://127.0.0.1:1", $errno, $errstr, 1,
STREAM_CLIENT_CONNECT, $context));
echo $errstr, PHP_EOL;

?>
--EXPECT--
bool(false)
so_rcvbuf context option must be between 1 and 2147483647
bool(false)
so_rcvbuf context option must be between 1 and 2147483647
bool(false)
so_rcvbuf context option must be between 1 and 2147483647
bool(false)
so_sndbuf context option must be between 1 and 2147483647
bool(false)
so_sndbuf context option must be between 1 and 2147483647
bool(false)
so_sndbuf context option must be between 1 and 2147483647
bool(false)
so_rcvbuf context option must be between 1 and 2147483647
47 changes: 47 additions & 0 deletions ext/standard/tests/network/so_rcvbuf_sndbuf_udp.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
--TEST--
stream_socket_server() SO_RCVBUF and SO_SNDBUF context options test with UDP
--EXTENSIONS--
sockets
--FILE--
<?php
function buffers($stream): array {
$sock = socket_import_stream($stream);
return [
socket_get_option($sock, SOL_SOCKET, SO_RCVBUF),
socket_get_option($sock, SOL_SOCKET, SO_SNDBUF),
];
}

$control = stream_socket_server("udp://127.0.0.1:0", $errno, $errstr, STREAM_SERVER_BIND);

if (!$control) {
die('Unable to create server');
}

[$rcvbuf, $sndbuf] = buffers($control);

// Shrinking is always honoured, while growing may be capped by the system maximum.
$context = stream_context_create(['socket' => [
'so_rcvbuf' => intdiv($rcvbuf, 4),
'so_sndbuf' => intdiv($sndbuf, 4),
]]);

$server = stream_socket_server("udp://127.0.0.1:0", $errno, $errstr, STREAM_SERVER_BIND, $context);

if (!$server) {
die('Unable to create server');
}

[$server_rcvbuf, $server_sndbuf] = buffers($server);
echo "Server buffers\n";
var_dump($server_rcvbuf < $rcvbuf);
var_dump($server_sndbuf < $sndbuf);

fclose($server);
fclose($control);

?>
--EXPECT--
Server buffers
bool(true)
bool(true)
Loading