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
5 changes: 4 additions & 1 deletion NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ PHP NEWS
. Added the "filter.max_filter_count" stream context option for php://filter
URLs. Using more than 16 filters without configuring this option is now
deprecated. (Sjoerd Langkemper)
. Fixed bug GH-23006 (phpcredits() full-page HTML title says phpinfo()).
(Weilin Du)
. The following functions now raise a ValueError when the $filename argument
contains NUL bytes: fileperms(), fileinode(), filesize(), fileowner(),
filegroup(), fileatime(), filemtime(), filectime(), filetype(),
Expand Down Expand Up @@ -605,7 +607,8 @@ PHP NEWS
. Added so_keepalive, tcp_keepidle, tcp_keepintvl and tcp_keepcnt stream
socket context options. (Jakub Zelenka)
. Added so_reuseaddr streams context socket option that allows disabling
address reuse. (Jakub Zelenka)
address resuse. (Jakub Zelenka)
. Added so_linger stream socket context option. (Jakub Zelenka)
. Fixed bug GH-20370 (User stream filters could violate typed property
constraints). (alexandre-daubois)
. Allowed filtered streams to be casted as fd for select. (Jakub Zelenka)
Expand Down
4 changes: 4 additions & 0 deletions UPGRADING
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,10 @@ PHP 8.6 UPGRADE NOTES
. Added stream socket context options so_keepalive, tcp_keepidle,
tcp_keepintvl and tcp_keepcnt that allow setting socket keepalive
options.
. Added stream socket context option so_linger that sets SO_LINGER on TCP
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.
. Allowed casting casting filtered streams as file descriptor for select.
. Added the "write_seek_mode stream" filter parameter for the bz2, iconv,
zlib, and string stream filters. This parameter must be set via an
Expand Down
1 change: 1 addition & 0 deletions UPGRADING.INTERNALS
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ PHP 8.6 INTERNALS UPGRADE NOTES
. EG(in_autoload) was renamed to EG(autoload_current_classnames) and no
longer is a pointer, but a directly embedded HashTable struct.
. Extended php_stream_filter_ops with seek method.
. php_print_info_htmlhead() now takes a title argument.
. zend_argument_error_variadic() now takes a new 'function' parameter.
. The param argument in the php_verror() function has been removed.
. The php_stream_wrapper_log_error() signature changed from
Expand Down
2 changes: 2 additions & 0 deletions ext/intl/dateformat/dateformat_helpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

#include "../intl_cppshims.h"

#include <limits>

#include <unicode/calendar.h>
#include <unicode/gregocal.h>

Expand Down
42 changes: 42 additions & 0 deletions ext/openssl/tests/stream_cafile_no_valid_certs.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
--TEST--
SSL cafile stream containing no valid certificates
--EXTENSIONS--
openssl
--SKIPIF--
<?php
if (!function_exists('proc_open')) die('skip no proc_open');
?>
--FILE--
<?php
$serverCode = <<<'CODE'
$server = stream_socket_server('tcp://127.0.0.1:0', $errno, $errstr);
phpt_notify_server_start($server);

$client = stream_socket_accept($server, 2);
if ($client) {
fclose($client);
}
CODE;

$clientCode = <<<'CODE'
$context = stream_context_create(['ssl' => [
'cafile' => 'file://%s',
]]);
var_dump(stream_socket_client(
'ssl://{{ ADDR }}',
timeout: 2,
context: $context,
));
CODE;
$clientCode = sprintf($clientCode, __DIR__ . '/plain.txt');

include 'ServerClientTestCase.inc';
ServerClientTestCase::getInstance()->run($clientCode, $serverCode);
?>
--EXPECTF--
Warning: stream_socket_client(): no valid certs found cafile stream: '%s' in %sServerClientTestCase.inc(%d) : eval()'d code on line 4

Warning: stream_socket_client(): Failed to enable crypto in %sServerClientTestCase.inc(%d) : eval()'d code on line 4

Warning: stream_socket_client(): Unable to connect to ssl://127.0.0.1:%d (Unknown error) in %sServerClientTestCase.inc(%d) : eval()'d code on line 4
bool(false)
13 changes: 6 additions & 7 deletions ext/openssl/xp_ssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -947,15 +947,14 @@ static long php_openssl_load_stream_cafile(X509_STORE *cert_store, const char *c
goto cert_start;
}

stream_complete: {
php_stream_close(stream);
if (buffer_active == 1) {
BIO_free(buffer);
}
stream_complete:
if (certs_added == 0) {
php_stream_warn(stream, DecodingFailed, "no valid certs found cafile stream: '%s'", cafile);
}

if (certs_added == 0) {
php_stream_warn(stream, DecodingFailed, "no valid certs found cafile stream: `%s'", cafile);
php_stream_close(stream);
if (buffer_active == 1) {
BIO_free(buffer);
}

return certs_added;
Expand Down
2 changes: 1 addition & 1 deletion ext/standard/credits.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
PHPAPI ZEND_COLD void php_print_credits(int flag) /* {{{ */
{
if (!sapi_module.phpinfo_as_text && flag & PHP_CREDITS_FULLPAGE) {
php_print_info_htmlhead();
php_print_info_htmlhead("phpcredits()");
}

if (!sapi_module.phpinfo_as_text) {
Expand Down
6 changes: 3 additions & 3 deletions ext/standard/info.c
Original file line number Diff line number Diff line change
Expand Up @@ -733,13 +733,13 @@ PHPAPI zend_string *php_get_uname(char mode)
/* }}} */

/* {{{ php_print_info_htmlhead */
PHPAPI ZEND_COLD void php_print_info_htmlhead(void)
PHPAPI ZEND_COLD void php_print_info_htmlhead(const char *title)
{
php_info_print("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"DTD/xhtml1-transitional.dtd\">\n");
php_info_print("<html xmlns=\"http://www.w3.org/1999/xhtml\">");
php_info_print("<head>\n");
php_info_print_style();
php_info_printf("<title>PHP %s - phpinfo()</title>", PHP_VERSION);
php_info_printf("<title>PHP %s - %s</title>", PHP_VERSION, title);
php_info_print("<meta name=\"ROBOTS\" content=\"NOINDEX,NOFOLLOW,NOARCHIVE\" />");
php_info_print("</head>\n");
php_info_print("<body><div class=\"center\">\n");
Expand All @@ -761,7 +761,7 @@ PHPAPI ZEND_COLD void php_print_info(int flag)
zend_string *php_uname;

if (!sapi_module.phpinfo_as_text) {
php_print_info_htmlhead();
php_print_info_htmlhead("phpinfo()");
} else {
php_info_print("phpinfo()\n");
}
Expand Down
2 changes: 1 addition & 1 deletion ext/standard/info.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
#define ZEND_LOGO_DATA_URI "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAPoAAAAvCAYAAADKH9ehAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAEWJJREFUeNrsXQl0VNUZvjNJSAgEAxHCGsNitSBFxB1l0boUW1pp3VAUrKLWKgUPUlEB13K0Yq1alaXWuh5EadWK1F0s1gJaoaCgQDRKBBJDVhKSzPR+zPfg5vLevCUzmZnwvnP+k8ybN3fevfff73/vBAJTHxc+khL5kr6T1ODk5nAgTRTWloghFVtEg/zfh2PkSvq9pJGSKiX9SdKittbJoD/PSYkrJD0vKeB4IsNNotfuUtHk/CM+IvijpF9KGiDpGEkLJZ3lC7qPeKKTpD9IWiDpUOfWPCi61ZeLvD2VIhTwp9QlTjK5NsIXdB/xxHmSpvD/OucWPSAyQw2+LfeG1SbXVra1Tqb785xUaNdMel0g7Iu5V1zPv6dJqpD0kKR/+ILuI55o8oeg1bFT0kWSOkraQxK+oPvw0TZR3ZY758foyQXf//ZxUFh0Q/GEfNf9gHkaJ6m7pHJJSyTt9tnXhxtBR2EGlnHCMbZMaHuHzX19JZ0u6VRJh0k6hM+BpMjnklZIelPSNhff3V5StkNlEWBMFm+3LcC+BW3GuZP2GvfmiEiCCMUzxZIKRGSt9zeML/fdGAW9JB3O8c6SlMZ+b5f0qaQiF7EpnieXY1auvZfG7zhSUk8RSS428F7M5xfsh1eAV/vxOzoq16sklZBqbdpo5H2qDPRQXoP3Ki0+20FSFyrZUgt+Rt/7KH2vZb8/t/iMG2Sy/0dI6sbvgHGoV8a3xErQb5Q0iTfHCplkzlkW7w+VNF3ST7QJUzFK0pVkDFiw+yV95uC7r5Z0k3CW2ApwIkrJ9B9IelfSh2SIlqC/pDFUZAVk0rQoMhk2GYswx+AtWvMKPtcyEckW37pPwsIHNAuBniDpYhEpBMmJwvibJL0gIlVh39r0C8UlczkXQ/mM6OtEzuf3RfPVAxUY47f5PStcGKPxpOMldbbxiBptPMavJX1PuQ/P/olyz12S7rD4PLyqBTQ8gyXVSOot6VK+dxR53wyl7POjkv7pkpcwpleJSCHP4eQjM0BB/ZuG4Hl9EO8mQx4ZQ0FfL+k+k+t4wNlULpkO24IGnSzpQklzKPDRAMvZ1eXz9uXfH/Pvx5Ie44C5zYQXUgDPj6LEnMCQ3AFkjjupjGF9/kJmxPw1oiquz+6dalXcCRSmYxwK0kDSRI71azb3Y+6GiMi6P/5ey3F3YpExjxdQoG61uX8gBetkh2OWFkUIVGUT1pS9yosZNu1nkl8uZH+mikhxkx1wz7mkB0WkXsKJFw1ZuSWKotY9wjNJS6mUy41JK5P0c2qCnBgIeQWZvEK7Dnf6WUljTT5TS7d0KwezkJShdWIeGeuKKJo7FktUQylcl0i6RtL/HH4OjP+wB0UTLTGHfubRDWyi1g7SaoZQ495z9w7RpaHKqHEfLeklEyWzk+7dl3TTu1KQCpV7+pBB4IWstFFAgvOpJnTL6DoW0xPbw3k/nIYkW+kbmHeXhUEABklazrBDBdzTDfyuBo5DPq1eoUk7ZbSk70l6n3MZjUdCDpQvMF/rezn7/hX7Xs8wsj/7rsrWdQxnZtrwwENUosJkDDZxTjOUkEH1ds6lzJyDZzGScRsonGNcMCIG+WgRKTRQ8Su2p7uRi/mlKjZKekREChS2KIOcTvfqp3RZDlM+cxnfv8Thc75Pt8kqo92VzNTbxBqcQlceivAdByHDIxbvFTMOLovyHAGGK3qc/jJDoDc4hpjABzBm4UAglBFqEAOqt8mB29ss4uJnNCHfSK/tVZMYEfMykt7Bcco1eDLDHCT8gmzzRdLHZL6wRSgzg6GIgVl8Xj2uhPA+oQn53yTdK2mVMC8NzuJ8zaSyM/ApxyzWCFJRvUQ3eQ29BTNFcRgt+FTl2g30zDZZtD/ZRMifE5ES6Y9MxqAHQ7XZikI9nd97j5p1f83GZTPr6Crt2sOcOB1zTYT8HrqjVRZx4wbSAt47SXn/YsZV9zp4zuvJgNGQRaszmoN1rBY6IH4dHiVHcA5dZd2zeIbPv8ZBkghYTQFTx/h1WvSz6c3kM5ewGG8Prvxc5DZWS2u+dypnM5Y3sIJMXmbxfXW0misZN56oxITnWsyl2fg+6+C+zWTefMWr68RwaYF271htHBZqCsKqL28wB/ACjYShrE9nUjfWmEU33A7woqbR4k5UlNk4yoYOzOHvtGs30KO1QgnlZC2VohGOIGn7WEvW0ZdoMeCHfBgdo8X++m3V+s2wEHKzJMblJom92+ne2SHDwT1gknUispPpJLrrVZqwLxTmy5F5jOdVS72F/b6UwlbrcEytrD00+a8l/ZUM82jEZd8peu8uNYS8JxNWqis5IYqQCy1rPUULh8Y7fOYal3zzmPb6aJN7zlf+32bBV9ESclNE85WUX4j4oNbl/fM1b2eoxX3jyXNqiDTP4Xe8Rm9ItfSjvAr6DM0d+o5MXW/CuHO0a7eZTLYT3KF9LktYZ/WdCI+IkoV+lFZ6l3J9OF14HdM0F3MrhXxFjJmqhh5FBera24XqxaCqL0UosK97Z2ku+yJaEqf4D62ByoROcjZuN78Xaa9zTBSzKvxvC+vlrmgWVPU2h4j4FCO5lZ+vNBnpYHHfOOX/PfR83eApTaGM8CLop5l88WSLWAOu4AiNme5owcBO1xhlLGO/eGAFkyYqrtFe5zKzqU7KBE5o/BAIiv7VJSK7qV4GhEF1XtSk0YseWl6lWYI+cXj6pigJLkH3Vk0qfebxe4q0JGOGSDxCWn/Nchk9qJgMfGKS87LDes1IHeVW0LszgaC6sPMYE5lBt4CzRcuy4lVMLKlWfWwcJ+YpxtcGjtOYfzRjTgNIlv0rnpyCveeHNFSJ/jUlonH/3nNYqyOU28qYhHOLbzVPqFc81JQDKxnQ5twLdmjfmQzlxU6eoZ/mma3y8D3VonlhUr6bElhMwJ81RseSxW+jfOYULdYGAw5s4WBtpeU0ijKwxnp/HCfn70piCNlMFEUU8/WpmnZe1Bq80r96m5yMkIwx9nnNHTWFs114q0ArM1HsiUY7j5/rKFIThdrrzR7agHyoy9vd3Ag64uEfKa+xjIKlLqtTUBB7FWgJrQ9joFl1d2cQ2wzHaeDXa6/ztO9Wx+OT+FrzSAKuV12ptOZp+ljnaVawk8uxDpnMZXYCGB3PXqe5sl7QQ5ubhhQR9B4mQpvjIR+gJgrbOxV0rK/rVUyXmyRWdI2a2YLEhVP3BwmN9sJ9BtQpKkxiSDOrUeUhaeQaPevKzKQ3oIVTSGatcynoRl29sIkh440a8pURNoz00Ab4Ts1obxCps1FKl8k5IpKbcmsgu6nz6ETQC+iSqoKKOPmVJBmYnDjHX4EozB9s7TgwykkyYS13URAHpmstYIloOP/HEi6Wx5a4+DwSpH2V18tTyHUPm3iQeS1s09ai4/0ntVgNRQmzHTRulGwaQNnei3FgHqPcMBEJlXrNioAaE8AcupKBd7ElBu1uTxCzg+dmKB4TahiQNX/OxssAb00Uzdeci4S3FYhEQdfkWCrc1cI2K+2EDhsP1OUxZGUnOWTmcgphV0UgZ4jUR1hLlBiuJfqJpb61CXimOrq8RqiEeu6TU3iMwdzYgWhUnWHDDKr0ptLar6USqmOfYYiGMMTUN/KgziGVTo+pNJHBBfF0zVAQc6N2DUL+tcO2Yc1Rk2ss+yBmOko43yCSCljJXAWA7PD4eAt6MBy2yiNACRvVVN05t40pPLYPsT+zlRDpOLG/Jt8OSGKhmnBpivV7q/Y6JkucVgkyWKb52rVZwl0tvNDi+AzRvKjfK1Dnjvpd1FhPEc1LBVsbqENXN35cFaPY2BIVGdlWYZKqgPPj/RythNtpcNycpoOxwAae0bGwhAkAQg01cfiDWDRqZtHhCqFQ5FAtOXKXh/Yh6Ci2N5YMUDW2SHg/N3scn02N++cnMIZCBdwS9gtApRxqDc6OlzWtSrdc8cJGlzP5fzZDri1tQNixISWL/5fSQvcVzfe/wzXfSG8Kuw03pHB/t5KMik+EYJ1EC1d0zCw6fofqRI2ZJwpvyxN4uPs0q/6UR2szyESobxatf3aa7jvfrT0DGPNpYV3H3CI0BYLGllQdy7TX14rUP/zzDHpuRp0EPLnJvH68Qij/RXnyIyku5Ea+5S3NO7s01q77eMY1qqY8T7Qs+4qtq+o2UWhjZO6HuWhjJBlZXWbAHvbFSTAxqMW+RbuG3VfviAP36tshujINh6Tr3kE0BNMl5x8Qq6+mVTdwrMlzpRrGaGPzVpw9NDNFngjoFZZzRCS/FRPXHRZT31X2MgfYTQYX1WE1moaaQJfKEFTs/camkXnUwt9YtNWPiuc67VmRlb0yiRgS/cAe7is0QXuTAm9kikM2DNc5OkeGRaMU8tq0TJHbUCOtezMeRfITiSv1PLLbGE5gb/NOB/1AuR1KlLETDltidyR4XIPasyEnc6eIbRa9kfNifFeXJOAnVJBiKfFCvobcLKccLHWojHJpIPH3iXQlpoNLrdcH44sucvmQOHHjZ9rDrGdbixVmbk/XGy4mtiKuoQDjmQpFJLs6wuSZvqKmL0ky6zOZLry+420UKUaue5ooyeqy9+iopgM989cp1Dcp16bSU1tOJbyFyjedTID5wOk6OAUFFXUDKFRLkmBM3xH7fzIJwPLsxexDMWP2b8g38DqN45ywCuH0VNuv+XmjwOYCjtUakbg6AkGlNoQGBMB5A9g8hh2g7zFE2U4F35FxfHfmwwbxcz3Yl32C/oAwPwDAS6UXdpOhXPZ27Trc9R/SLTla0zzGoXl2QAexnLVZJB/CZMpV7HthfL4lJIrb54u+tdv3/rCiSbw+k88yM9ZxXgKwlHmZycq13iSr0KeMHmUZw6r1VICrLT4D5fy4wq/5DAvfjaWC9oAd9KxwTNUJynUjL+EqpwSTME1zOWMBuIxmZ7p9RCsNq+NmdxW09I1MdNkJeYZNHsIt0qKEO2Z4kvmHadS+Xqv2cqzc93rpuhdl54tg2DISuJljBW3uZjMHrAPqHOYK6zPIM23G2+14Rts4cyLbdxo3Y667UskOo/W/m/PwRhQBwZFkT2vXzDbTtLMZCyfP1155bbfDrpjKZoYH41bO+d97jmEgMPVxFMF0iHESIkiNtDhKuwV058cw0dBZNP+lFsSU/6VWf0E4P/x+IF2eJnokr4uW/2jAKPYjjRb7Cxef70c3qsCl0im1Gj/Uu2eF6sWo0rUiTQq7zS+pYjywnXYwcyOZfI4mKgHj9N2ttHqbRfSlQXhjw5XXy4S7ZbzOovkxVRsphHp8ia3HlyleZS1zHcvoVrdjuNFdEe7edGHzSbpSria/WZ3+cxYV5DCx/4w7FUfyfTW0WO+i7x2YrzKUXZFw/sut+OxJDGkHUxEZPwgCquQcIgxZR9oXekDQk8FF60bqwocupaIoEz6EmaC3C+0Ro6Wgp4eb2tpPJqN+4xXFXQ3TfUfCc5PDNnLZDpLIV1NADKyjZa87mHgmWX57bYdIfIY3pdCGf43xQUXI62kBn3fZxi4SPC8crIjDQ4yzFAaz/XcPJn7xf03VRzIB5Z7qCbBzPQi5jga2E9bCD+ELug8ficEZCk/Cmj8Ro3aLtLxDR1/QffhIHNRTUZCf+S5G7SJBp2b7G31B9+EjcVAFEInZQ2LU7jiN1zf4gu7DR+KwTvkfO9bGx6BNnEQ8XXmN5cT3fEH34SNxwN4A9dgknIEwyWNbeRTwV7WYHBVwFQfbwKb7vOUjiYAiKVT1PczXqCLD/n5UbuLcNxTKoCgExSFNmsFCHI6iJBQFnUbqqbWPHyFceDAOrC/oPpIN+FVaVLrNUa6dLPbvoEQdO4pd1OUylBVkCutsOkqosbNvwcE6qL6g+0hG3MY4ejots1pT3kE4P9QDdfuLKeDfHswD6gu6j2TF2yQcLoqEGurre9EdP1QTfmxJRdn0NlrvD+jmY69Egz+UQvxfgAEALJ4EcRDa/toAAAAASUVORK5CYII="

BEGIN_EXTERN_C()
PHPAPI void php_print_info_htmlhead(void);
PHPAPI void php_print_info_htmlhead(const char *title);
PHPAPI void php_print_info(int flag);
PHPAPI void php_print_style(void);
PHPAPI void php_info_print_style(void);
Expand Down
18 changes: 18 additions & 0 deletions ext/standard/tests/general_functions/phpcredits_title.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
--TEST--
phpcredits() full-page HTML title
--POST--
dummy=x
--FILE--
<?php
ob_start();
$result = phpcredits();
$output = ob_get_clean();

var_dump($result);
var_dump(str_contains($output, '<title>PHP ' . PHP_VERSION . ' - phpcredits()</title>'));
var_dump(str_contains($output, '<title>PHP ' . PHP_VERSION . ' - phpinfo()</title>'));
?>
--EXPECT--
bool(true)
bool(true)
bool(false)
82 changes: 82 additions & 0 deletions ext/standard/tests/network/so_linger.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
--TEST--
stream_socket_server() and stream_socket_client() SO_LINGER context option test
--EXTENSIONS--
sockets
--FILE--
<?php
// Test server with SO_LINGER enabled
$server_context = stream_context_create([
'socket' => [
'so_linger' => 10,
]
]);

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

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

$addr = stream_socket_get_name($server, false);
$port = (int)substr(strrchr($addr, ':'), 1);

// Test client with SO_LINGER enabled
$client_context = stream_context_create([
'socket' => [
'so_linger' => 8,
]
]);

$client = stream_socket_client("tcp://127.0.0.1:$port", $errno, $errstr, 30,
STREAM_CLIENT_CONNECT, $client_context);

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

$accepted = stream_socket_accept($server, 1);

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

// macOS expresses SO_LINGER in ticks, SO_LINGER_SEC in seconds.
$so_linger = defined('SO_LINGER_SEC') ? SO_LINGER_SEC : SO_LINGER;

// Verify the listening socket
$listen_sock = socket_import_stream($server);
$listen_linger = socket_get_option($listen_sock, SOL_SOCKET, $so_linger);
echo "Listen SO_LINGER\n";
var_dump($listen_linger['l_onoff'] > 0);
var_dump($listen_linger['l_linger']);

// Verify server side (accepted connection, inherits from the listening socket)
$server_sock = socket_import_stream($accepted);
$server_linger = socket_get_option($server_sock, SOL_SOCKET, $so_linger);
echo "Server SO_LINGER\n";
var_dump($server_linger['l_onoff'] > 0);
var_dump($server_linger['l_linger']);

// Verify client side
$client_sock = socket_import_stream($client);
$client_linger = socket_get_option($client_sock, SOL_SOCKET, $so_linger);
echo "Client SO_LINGER\n";
var_dump($client_linger['l_onoff'] > 0);
var_dump($client_linger['l_linger']);

fclose($accepted);
fclose($client);
fclose($server);

?>
--EXPECT--
Listen SO_LINGER
bool(true)
int(10)
Server SO_LINGER
bool(true)
int(10)
Client SO_LINGER
bool(true)
int(8)
36 changes: 36 additions & 0 deletions main/network.c
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,24 @@ php_socket_t php_network_bind_socket_to_local_addr_ex(const char *host, unsigned

/* Set socket values if provided */
if (sockvals != NULL) {
#ifdef SO_LINGER
if (sockvals->mask & PHP_SOCKVAL_SO_LINGER) {
/* l_linger is an unsigned short on Windows, so clamp rather than
* truncate: a truncated value may still be in range and would then
* be applied silently (e.g. 65536 becoming 0, an abortive close). */
unsigned short secs = sockvals->linger > USHRT_MAX
? USHRT_MAX : (unsigned short)sockvals->linger;
struct linger linger_val = {
.l_onoff = (sockvals->linger > 0),
.l_linger = sockvals->linger > 0 ? secs : 0
};
#ifdef SO_LINGER_SEC
setsockopt(sock, SOL_SOCKET, SO_LINGER_SEC, (char*)&linger_val, sizeof(linger_val));
#else
setsockopt(sock, SOL_SOCKET, SO_LINGER, (char*)&linger_val, sizeof(linger_val));
#endif
}
#endif
#if defined(TCP_KEEPIDLE)
if (sockvals->mask & PHP_SOCKVAL_TCP_KEEPIDLE) {
setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, (char*)&sockvals->keepalive.keepidle, sizeof(sockvals->keepalive.keepidle));
Expand Down Expand Up @@ -1021,6 +1039,24 @@ php_socket_t php_network_connect_socket_to_host_ex(const char *host, unsigned sh

/* Set socket values if provided */
if (sockvals != NULL) {
#ifdef SO_LINGER
if (sockvals->mask & PHP_SOCKVAL_SO_LINGER) {
/* l_linger is an unsigned short on Windows, so clamp rather than
* truncate: a truncated value may still be in range and would then
* be applied silently (e.g. 65536 becoming 0, an abortive close). */
unsigned short secs = sockvals->linger > USHRT_MAX
? USHRT_MAX : (unsigned short)sockvals->linger;
struct linger linger_val = {
.l_onoff = (sockvals->linger > 0),
.l_linger = sockvals->linger > 0 ? secs : 0
};
#ifdef SO_LINGER_SEC
setsockopt(sock, SOL_SOCKET, SO_LINGER_SEC, (char*)&linger_val, sizeof(linger_val));
#else
setsockopt(sock, SOL_SOCKET, SO_LINGER, (char*)&linger_val, sizeof(linger_val));
#endif
}
#endif
#if defined(TCP_KEEPIDLE)
if (sockvals->mask & PHP_SOCKVAL_TCP_KEEPIDLE) {
setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, (char*)&sockvals->keepalive.keepidle, sizeof(sockvals->keepalive.keepidle));
Expand Down
2 changes: 2 additions & 0 deletions main/php_network.h
Original file line number Diff line number Diff line change
Expand Up @@ -269,12 +269,14 @@ typedef struct {
#define PHP_SOCKVAL_TCP_KEEPIDLE (1 << 1)
#define PHP_SOCKVAL_TCP_KEEPCNT (1 << 2)
#define PHP_SOCKVAL_TCP_KEEPINTVL (1 << 3)
#define PHP_SOCKVAL_SO_LINGER (1 << 4)

#define PHP_SOCKVAL_IS_SET(sockvals, opt) ((sockvals)->mask & (opt))

typedef struct {
unsigned int mask;
int tcp_nodelay;
int linger;
struct {
int keepidle;
int keepcnt;
Expand Down
20 changes: 20 additions & 0 deletions main/streams/xp_socket.c
Original file line number Diff line number Diff line change
Expand Up @@ -759,6 +759,16 @@ static inline int php_tcp_sockop_bind(php_stream *stream, php_netstream_data_t *
}
#endif

#ifdef SO_LINGER
if (PHP_STREAM_XPORT_IS_TCP(stream)
&& PHP_STREAM_CONTEXT(stream)
&& (tmpzval = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "socket", "so_linger")) != NULL
) {
sockvals.mask |= PHP_SOCKVAL_SO_LINGER;
sockvals.linger = (int)zval_get_long(tmpzval);
}
#endif

#ifdef SO_KEEPALIVE
if (PHP_STREAM_XPORT_IS_TCP(stream) /* SO_KEEPALIVE is only applicable for TCP */
&& PHP_STREAM_CONTEXT(stream)
Expand Down Expand Up @@ -887,6 +897,16 @@ static inline int php_tcp_sockop_connect(php_stream *stream, php_netstream_data_
sockopts |= STREAM_SOCKOP_TCP_NODELAY;
}

#ifdef SO_LINGER
if (PHP_STREAM_XPORT_IS_TCP(stream)
&& PHP_STREAM_CONTEXT(stream)
&& (tmpzval = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "socket", "so_linger")) != NULL
) {
sockvals.mask |= PHP_SOCKVAL_SO_LINGER;
sockvals.linger = (int)zval_get_long(tmpzval);
}
#endif

#ifdef SO_KEEPALIVE
if (PHP_STREAM_XPORT_IS_TCP(stream) /* SO_KEEPALIVE is only applicable for TCP */
&& PHP_STREAM_CONTEXT(stream)
Expand Down
Loading