Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
2236e6b
stream: remove php_stream_fopen_with_path() function (#22793)
Girgias Jul 19, 2026
04f3d28
ext/standard: reject a dechunk chunk size that overflows size_t
iliaal Jul 16, 2026
817f6d2
Merge branch 'PHP-8.4' into PHP-8.5
iliaal Jul 19, 2026
c461266
Merge branch 'PHP-8.5'
iliaal Jul 19, 2026
34c686a
stream: remove path parameter in stream error functions (#22792)
Girgias Jul 19, 2026
32a0f3b
IO copy API for stream copying (#20399)
bukka Jul 19, 2026
cfbe114
Add UPGRADING.INTERNALS entry after function removal
Girgias Jul 19, 2026
fdc5b8f
Reorganise UPGRADING.INTERNALS to be more legible (#22808)
Girgias Jul 19, 2026
e101415
stream: improve bugfix, check class is instantiable prior to register…
Girgias Jul 19, 2026
6455aab
Reflection: integer types cleanup
DanielEScherzer Jul 17, 2026
07b5905
Reflection: mark a whole bunch of pointers as `const`
DanielEScherzer Jul 17, 2026
b8dc2a8
Reflection: replace `struct _zend_arg_info` with `zend_arg_info`
DanielEScherzer Jul 17, 2026
c06e86d
Reflection: consistent pointer type declaration spacing
DanielEScherzer Jul 17, 2026
7914410
Reflection: remove unused parameter from `get_ce_from_scope_name()`
DanielEScherzer Jul 17, 2026
b043ea3
Reflection: whitespace cleanup
DanielEScherzer Jul 17, 2026
6210d5c
Voidify zend_std_unset_static_property() (#22809)
Girgias Jul 19, 2026
8d9ed39
stream: registering cannot fail, thus voidify function (#22811)
Girgias Jul 19, 2026
5c4bff6
main: convert sys_temp_dir global to zend_string* (#22812)
Girgias Jul 19, 2026
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
4 changes: 4 additions & 0 deletions .github/workflows/unit-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,17 @@ on:
push:
paths:
- 'main/network.c'
- 'main/io/**'
- 'main/php_io.h'
- 'tests/unit/**'
- '.github/workflows/unit-tests.yml'
branches:
- master
pull_request:
paths:
- 'main/network.c'
- 'main/io/**'
- 'main/php_io.h'
- 'tests/unit/**'
- '.github/workflows/unit-tests.yml'
branches:
Expand Down
5 changes: 5 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ PHP NEWS
TCP_USER_TIMEOUT, and SO_LINGER options. (Weilin Du)
. Fixed various memory related issues in ext/sockets. (David Carlier)

- Streams:
. Added a new IO copy API used by php_stream_copy_to_stream_ex() that
leverages platform primitives (sendfile, splice, copy_file_range,
TransmitFile) for faster stream copying. (Jakub Zelenka, David Carlier)

16 Jul 2026, PHP 8.6.0alpha2

- Core:
Expand Down
111 changes: 61 additions & 50 deletions UPGRADING.INTERNALS
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,8 @@ PHP 8.6 INTERNALS UPGRADE NOTES
1. Internal API changes
========================

. ZSTR_INIT_LITERAL(), zend_string_starts_with_literal(), and
zend_string_starts_with_literal_ci() now support strings containing NUL
bytes. Passing non-literal char* is no longer supported.
. Added zend_string_equals_cstr_ci().
- Removed:
. The misnamed ZVAL_IS_NULL() has been removed. Use Z_ISNULL() instead.
. New zend_class_entry.ce_flags2 and zend_function.fn_flags2 fields were
added, given the primary flags were running out of bits.
. The zval_is_true() alias of zend_is_true() has been removed. Call
zend_is_true() directly instead.
. The _zval_get_*() compatibility macros for PHP 7.2 have been removed
Expand All @@ -42,45 +37,13 @@ PHP 8.6 INTERNALS UPGRADE NOTES
needs to be obtained use the zend_get_callable_zval_from_fcc() function
instead. If this was used to store a callable, then an FCC should be
stored instead.
. The zend_active_function{_ex}() functions now return a const zend_function
pointer.
. The zend_get_call_trampoline_func() API now takes the __call or
__callStatic zend_function* instead of a CE and a boolean argument.
. The zend_exception_save() and zend_exception_restore() functions were
removed.
. The zend_set_hash_symbol() API has been removed.
. Added zend_hash_str_lookup().
. The WRONG_PARAM_COUNT and ZEND_WRONG_PARAM_COUNT() macros have been
removed. Call zend_wrong_param_count(); followed by RETURN_THROWS();
instead.
. PHP_HAVE_STREAMS macro removed from <php.h>.
. zend_function.arg_info is now always a zend_arg_info*. Before, it was a
zend_internal_arg_info on internal functions, unless the
ZEND_ACC_USER_ARG_INFO flag was set.
. Added zend_ast_call_get_args() to fetch the argument node from any call
node.
. The zend_exception_save() and zend_exception_restore() functions were
removed.
. Internal functions that return by reference are now expected to
automatically unwrap references when the result of the call is stored in an
IS_TMP_VAR variable. This may be achieved by calling the
zend_return_unwrap_ref() function.
. The php_math_round_mode_from_enum() function now takes a
zend_enum_RoundingMode parameter.
. Added Z_PARAM_ENUM().
. Added zend_enum_fetch_case_id().
. Added zend_enum_get_case_by_id().
. Added zend_bin2hex() and zend_bin2hex_str() as helper functions to remove
dependencies on /ext/hash in various extensions.
. ZEND_INI_GET_ADDR() is now a void* pointer instead of a char* pointer. This
more correctly represents the generic nature of the returned pointer and
allows to remove explicit casts, but possibly breaks pointer arithmetic
performed on the result.
. The zend_dval_to_lval_cap() function no longer takes a second
zend_string* parameter.
. EG(in_autoload) was renamed to EG(autoload_current_classnames) and no
longer is a pointer, but a directly embedded HashTable struct.
. Added a C23_ENUM() helper macro to define forward-compatible fixed-size
enums.
. Extended php_stream_filter_ops with seek method.
. The INI_STR(), INI_INT(), INI_FLT(), and INI_BOOL() macros have been
removed. Instead new zend_ini_{bool|long|double|str|string}_literal()
macros have been added. This fixes an internal naming inconsistency as
Expand All @@ -90,13 +53,8 @@ PHP 8.6 INTERNALS UPGRADE NOTES
unused. If this behaviour is required fall back to the zend_ini_*
functions.
. The unused ZEND_AST_PARENT_PROPERTY_HOOK_CALL has been removed.
. ZEND_AST_METHOD_REFERENCE has been renamed to
ZEND_AST_TRAIT_METHOD_REFERENCE.
. The EMPTY_SWITCH_DEFAULT_CASE() macro has been removed. Use
default: ZEND_UNREACHABLE(); instead.
. Functions using zend_forbid_dynamic_call() *must* be flagged with
ZEND_ACC2_FORBID_DYN_CALLS (@forbid-dynamic-calls in stubs). In debug
builds, failing to include that flag will lead to assertion failures.
. The ZEND_RESULT_CODE type has been removed. Use zend_result directly.
. The zend_parse_parameters_none_throw(), zend_parse_parameters_throw(),
and ZEND_PARSE_PARAMS_THROW have been removed due to being misleading,
Expand All @@ -115,16 +73,63 @@ PHP 8.6 INTERNALS UPGRADE NOTES
have been removed, because they are unsafe by relying on the zvals
having a specific type. Use zend_binary_strcmp() / zend_binary_strncmp(),
string_compare_function() or similar instead.
. Added zend_fcall_info.consumed_args together with
zend_fci_consumed_arg(), which allows moving a selected callback argument
instead of copying it in zend_call_function(). Currently only a single
consumed argument is supported.
. Added ZEND_CONTAINER_OF().
. The OPENBASEDIR_CHECKPATH() compatibility macro has been removed, instead
use php_check_open_basedir() directly.
. The Z_CONSTANT(), Z_CONSTANT_P(), Z_OPT_CONSTANT(), and
Z_OPT_CONSTANT_P() macros have been removed. Check for IS_CONSTANT_AST
directly.
. The {_}php_stream_fopen_with_path() functions have been removed as they are
unused.

- Changed:
. Internal functions that return by reference are now expected to
automatically unwrap references when the result of the call is stored in an
IS_TMP_VAR variable. This may be achieved by calling the
zend_return_unwrap_ref() function.
. ZEND_AST_METHOD_REFERENCE has been renamed to
ZEND_AST_TRAIT_METHOD_REFERENCE.
. Functions using zend_forbid_dynamic_call() *must* be flagged with
ZEND_ACC2_FORBID_DYN_CALLS (@forbid-dynamic-calls in stubs). In debug
builds, failing to include that flag will lead to assertion failures.
. The zend_get_call_trampoline_func() API now takes the __call or
__callStatic zend_function* instead of a CE and a boolean argument.
. ZSTR_INIT_LITERAL(), zend_string_starts_with_literal(), and
zend_string_starts_with_literal_ci() now support strings containing NUL
bytes. Passing non-literal char* is no longer supported.
. Added zend_string_equals_cstr_ci().
. The zend_active_function{_ex}() functions now return a const zend_function
pointer.
. zend_function.arg_info is now always a zend_arg_info*. Before, it was a
zend_internal_arg_info on internal functions, unless the
ZEND_ACC_USER_ARG_INFO flag was set.
. ZEND_INI_GET_ADDR() is now a void* pointer instead of a char* pointer. This
more correctly represents the generic nature of the returned pointer and
allows to remove explicit casts, but possibly breaks pointer arithmetic
performed on the result.
. The zend_dval_to_lval_cap() function no longer takes a second
zend_string* parameter.
. 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.

- Added:
. New zend_class_entry.ce_flags2 and zend_function.fn_flags2 fields were
added, given the primary flags were running out of bits.
. Added zend_hash_str_lookup().
. Added zend_ast_call_get_args() to fetch the argument node from any call
node.
. Added Z_PARAM_ENUM().
. Added zend_enum_fetch_case_id().
. Added zend_enum_get_case_by_id().
. Added zend_bin2hex() and zend_bin2hex_str() as helper functions to remove
dependencies on /ext/hash in various extensions.
. Added a C23_ENUM() helper macro to define forward-compatible fixed-size
enums.
. Added zend_fcall_info.consumed_args together with
zend_fci_consumed_arg(), which allows moving a selected callback argument
instead of copying it in zend_call_function(). Currently only a single
consumed argument is supported.
. Added ZEND_CONTAINER_OF().
. Added zend_reflection_property_set_raw_value_without_lazy_initialization(),
zend_reflection_property_set_raw_value() to expose the functionality of
ReflectionProperty::setRawValueWithoutLazyInitialization() and
Expand All @@ -136,6 +141,10 @@ PHP 8.6 INTERNALS UPGRADE NOTES
. Added zend_compile_ast().
. Added zend_check_type_ex().
. Added zend_create_partial_closure().
. Added a new IO copy API in <php_io.h>. php_io_copy() copies bytes between
file descriptors using the most efficient platform primitive available
(sendfile, splice, copy_file_range, TransmitFile), and is now used by
php_stream_copy_to_stream_ex(). The mmap-based copy fallback was removed.

========================
2. Build system changes
Expand Down Expand Up @@ -219,6 +228,8 @@ PHP 8.6 INTERNALS UPGRADE NOTES
. _php_error_log() now accepts zend_string* values instead of char*.
. _php_error_log_ex() has been removed.
. php_mail()'s extra_cmd parameter is now a zend_string*.
. The php_math_round_mode_from_enum() function now takes a
zend_enum_RoundingMode parameter.

- ext/uri:
. The value parameter of the php_uri_property_handler_write callback is now
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ try {
}
?>
--EXPECTF--
ERR#2: include(class://non.existent.Class): Failed to open stream: "CLWrapper::stream_open" call failed @ include
ERR#2: include(): Failed to open stream: "CLWrapper::stream_open" call failed @ include
ERR#2: include(): Failed opening 'class://non.existent.Class' for inclusion (include_path='%s') @ include

Fatal error: Uncaught Exception: Failed loading class://non.existent.Class in %s
Expand Down
4 changes: 2 additions & 2 deletions Zend/tests/bug30998.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@ set_error_handler('my_error');
$f = fopen("/tmp/blah", "r");
?>
--EXPECTF--
fopen(/tmp/blah): Failed to open stream: %s (2) in %s:%d
fopen(): Failed to open stream: %s (2) in %s:%d

Warning: fopen(/tmp/blah): Failed to open stream: %s in %s on line %d
Warning: fopen(): Failed to open stream: %s in %s on line %d
4 changes: 2 additions & 2 deletions Zend/tests/bug60909_1.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ set_error_handler(function($errno, $errstr, $errfile, $errline){
require 'notfound.php';
?>
--EXPECTF--
error(require(notfound.php): Failed to open stream: %s)
error(require(): Failed to open stream: %s)
Fatal error: Uncaught Exception: Foo in %sbug60909_1.php:5
Stack trace:
#0 %s(%d): {closure:%s:%d}(2, 'require(notfoun...', '%s', 8)
#0 %s(%d): {closure:%s:%d}(2, 'require(): Fail...', '%s', 8)
#1 %sbug60909_1.php(8): require()
#2 {main}
thrown in %sbug60909_1.php on line 5
Expand Down
2 changes: 1 addition & 1 deletion Zend/tests/gh11735_2.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,5 @@ stream_wrapper_register('foo', 'FooWrapper');
var_dump(fopen('foo://bar', 'r'));
?>
--EXPECTF--
Warning: fopen(foo://bar): Failed to open stream: "FooWrapper::stream_open" call failed in %s on line %d
Warning: fopen(): Failed to open stream: "FooWrapper::stream_open" call failed in %s on line %d
bool(false)
2 changes: 1 addition & 1 deletion Zend/tests/include_stat_is_quiet.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ try {

?>
--EXPECTF--
Warning: require_once(doesnt_exist.php): Failed to open stream: No such file or directory in %s on line %d
Warning: require_once(): Failed to open stream: No such file or directory in %s on line %d

Fatal error: Uncaught Error: Failed opening required 'doesnt_exist.php' (include_path='test://foo:test://bar') in %s:%d
Stack trace:
Expand Down
2 changes: 1 addition & 1 deletion Zend/tests/oss_fuzz_64209.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ oss-fuzz #64209: Fix in-place modification of filename in php_message_handler_fo
require '://@';
?>
--EXPECTF--
Warning: require(://@): Failed to open stream: No such file or directory in %s on line %d
Warning: require(): Failed to open stream: No such file or directory in %s on line %d

Fatal error: Uncaught Error: Failed opening required '://@' (include_path='%s') in %s:%d
Stack trace:
Expand Down
2 changes: 1 addition & 1 deletion Zend/tests/require_once_warning_to_exception.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@ try {

?>
--EXPECT--
require_once(does-not-exist.php): Failed to open stream: No such file or directory
require_once(): Failed to open stream: No such file or directory
3 changes: 1 addition & 2 deletions Zend/zend_object_handlers.c
Original file line number Diff line number Diff line change
Expand Up @@ -2178,10 +2178,9 @@ ZEND_API zval *zend_std_get_static_property(zend_class_entry *ce, zend_string *p
return zend_std_get_static_property_with_info(ce, property_name, type, &prop_info);
}

ZEND_API ZEND_COLD bool zend_std_unset_static_property(const zend_class_entry *ce, const zend_string *property_name) /* {{{ */
ZEND_API ZEND_COLD void zend_std_unset_static_property(const zend_class_entry *ce, const zend_string *property_name) /* {{{ */
{
zend_throw_error(NULL, "Attempt to unset static property %s::$%s", ZSTR_VAL(ce->name), ZSTR_VAL(property_name));
return 0;
}
/* }}} */

Expand Down
2 changes: 1 addition & 1 deletion Zend/zend_object_handlers.h
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ ZEND_API void zend_class_init_statics(zend_class_entry *ce);
ZEND_API zend_function *zend_std_get_static_method(const zend_class_entry *ce, zend_string *function_name_strval, const zval *key);
ZEND_API zval *zend_std_get_static_property_with_info(zend_class_entry *ce, zend_string *property_name, int type, struct _zend_property_info **prop_info);
ZEND_API zval *zend_std_get_static_property(zend_class_entry *ce, zend_string *property_name, int type);
ZEND_API ZEND_COLD bool zend_std_unset_static_property(const zend_class_entry *ce, const zend_string *property_name);
ZEND_API ZEND_COLD void zend_std_unset_static_property(const zend_class_entry *ce, const zend_string *property_name);
ZEND_API zend_function *zend_std_get_constructor(zend_object *object);
ZEND_API struct _zend_property_info *zend_get_property_info(const zend_class_entry *ce, zend_string *member, int silent);
ZEND_API HashTable *zend_std_get_properties(zend_object *object);
Expand Down
14 changes: 14 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,9 @@ AC_SEARCH_LIBS([Pgrab], [proc])
dnl Haiku does not have network api in libc.
AC_SEARCH_LIBS([setsockopt], [network])

dnl Solaris/illumos provide sendfile() in libsendfile; libc on Linux/FreeBSD.
AC_SEARCH_LIBS([sendfile], [sendfile])

dnl Check for openpty. It may require linking against libutil or libbsd.
AC_CHECK_FUNCS([openpty],,
[AC_SEARCH_LIBS([openpty], [util bsd], [AC_DEFINE([HAVE_OPENPTY], [1])])])
Expand Down Expand Up @@ -588,10 +591,12 @@ AC_CHECK_FUNCS(m4_normalize([
putenv
reallocarray
scandir
sendfile
setenv
setitimer
shutdown
sigprocmask
splice
statfs
statvfs
std_syslog
Expand Down Expand Up @@ -1685,6 +1690,15 @@ PHP_ADD_SOURCES_X([main],
[PHP_FASTCGI_OBJS],
[no])

PHP_ADD_SOURCES([main/io], m4_normalize([
php_io.c
php_io_copy_linux.c
php_io_copy_freebsd.c
php_io_copy_solaris.c
php_io_copy_macos.c
]),
[-DZEND_ENABLE_STATIC_TSRMLS_CACHE=1])

PHP_ADD_SOURCES([main/poll], m4_normalize([
poll_backend_epoll.c
poll_backend_eventport.c
Expand Down
2 changes: 1 addition & 1 deletion ext/bz2/tests/001.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,6 @@ bzopen(): Argument #2 ($mode) must be either "r" or "w"
bzopen(): Argument #2 ($mode) must be either "r" or "w"
bzopen(): Argument #2 ($mode) must be either "r" or "w"

Warning: bzopen(no_such_file): Failed to open stream: No such file or directory in %s on line %d
Warning: bzopen(): Failed to open stream: No such file or directory in %s on line %d
bool(false)
resource(%d) of type (stream)
4 changes: 2 additions & 2 deletions ext/bz2/tests/002.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,10 @@ bool(false)
resource(%d) of type (stream)
resource(%d) of type (stream)

Warning: fopen(bz_open_002.txt): Failed to open stream: `br' is not a valid mode for fopen in %s on line %d
Warning: fopen(): Failed to open stream: `br' is not a valid mode for fopen in %s on line %d
bzopen(): Argument #1 ($file) must be of type string or file-resource, false given

Warning: fopen(bz_open_002.txt): Failed to open stream: `br' is not a valid mode for fopen in %s on line %d
Warning: fopen(): Failed to open stream: `br' is not a valid mode for fopen in %s on line %d
bzopen(): Argument #1 ($file) must be of type string or file-resource, false given

Warning: bzopen(): cannot write to a stream opened in read only mode in %s on line %d
Expand Down
16 changes: 8 additions & 8 deletions ext/dba/tests/dba_cdb_creation_matrix.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -25,35 +25,35 @@ clean_creation_tests($handler);
=== OPENING NON-EXISTING FILE ===
Mode parameter is "rl":

Warning: dba_open(cdb_not_existing.db): Failed to open stream: No such file or directory in %s on line %d
Warning: dba_open(): Failed to open stream: No such file or directory in %s on line %d
Opening DB failed
Mode parameter is "rd":

Warning: dba_open(cdb_not_existing.db): Failed to open stream: No such file or directory in %s on line %d
Warning: dba_open(): Failed to open stream: No such file or directory in %s on line %d
Opening DB failed
Mode parameter is "r-":

Warning: dba_open(cdb_not_existing.db): Failed to open stream: No such file or directory in %s on line %d
Warning: dba_open(): Failed to open stream: No such file or directory in %s on line %d
Opening DB failed
Mode parameter is "r":

Warning: dba_open(cdb_not_existing.db): Failed to open stream: No such file or directory in %s on line %d
Warning: dba_open(): Failed to open stream: No such file or directory in %s on line %d
Opening DB failed
Mode parameter is "wl":

Warning: dba_open(cdb_not_existing.db): Failed to open stream: No such file or directory in %s on line %d
Warning: dba_open(): Failed to open stream: No such file or directory in %s on line %d
Opening DB failed
Mode parameter is "wd":

Warning: dba_open(cdb_not_existing.db): Failed to open stream: No such file or directory in %s on line %d
Warning: dba_open(): Failed to open stream: No such file or directory in %s on line %d
Opening DB failed
Mode parameter is "w-":

Warning: dba_open(cdb_not_existing.db): Failed to open stream: No such file or directory in %s on line %d
Warning: dba_open(): Failed to open stream: No such file or directory in %s on line %d
Opening DB failed
Mode parameter is "w":

Warning: dba_open(cdb_not_existing.db): Failed to open stream: No such file or directory in %s on line %d
Warning: dba_open(): Failed to open stream: No such file or directory in %s on line %d
Opening DB failed
Mode parameter is "cl":

Expand Down
Loading
Loading