From 95b4710fe2f174592a3b06b628c47f8a434f161a Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Tue, 30 Sep 2025 20:29:14 +0200 Subject: [PATCH 01/68] stream: add initial stream errors API --- configure.ac | 1 + ext/standard/basic_functions.c | 1 + ext/standard/file.h | 4 +- main/php_streams.h | 3 + main/streams/php_stream_errors.h | 167 ++++++++ main/streams/stream_errors.c | 553 +++++++++++++++++++++++++++ main/streams/stream_errors.stub.php | 16 + main/streams/stream_errors_arginfo.h | 39 ++ main/streams/streams.c | 149 +------- win32/build/config.w32 | 2 +- 10 files changed, 794 insertions(+), 141 deletions(-) create mode 100644 main/streams/php_stream_errors.h create mode 100644 main/streams/stream_errors.c create mode 100644 main/streams/stream_errors.stub.php create mode 100644 main/streams/stream_errors_arginfo.h diff --git a/configure.ac b/configure.ac index 214c0ab91b2a5..024c86772cd16 100644 --- a/configure.ac +++ b/configure.ac @@ -1689,6 +1689,7 @@ PHP_ADD_SOURCES([main/streams], m4_normalize([ memory.c mmap.c plain_wrapper.c + stream_errors.c streams.c transports.c userspace.c diff --git a/ext/standard/basic_functions.c b/ext/standard/basic_functions.c index fbbeeb0b433f4..05821094fc048 100644 --- a/ext/standard/basic_functions.c +++ b/ext/standard/basic_functions.c @@ -336,6 +336,7 @@ PHP_MINIT_FUNCTION(basic) /* {{{ */ #endif BASIC_MINIT_SUBMODULE(exec) + BASIC_MINIT_SUBMODULE(stream_errors) BASIC_MINIT_SUBMODULE(user_streams) php_register_url_stream_wrapper("php", &php_stream_php_wrapper); diff --git a/ext/standard/file.h b/ext/standard/file.h index f8faebd028293..a3c84791cc1ee 100644 --- a/ext/standard/file.h +++ b/ext/standard/file.h @@ -34,6 +34,7 @@ PHPAPI PHP_FUNCTION(ftell); PHPAPI PHP_FUNCTION(fseek); PHPAPI PHP_FUNCTION(fpassthru); +PHP_MINIT_FUNCTION(stream_errors); PHP_MINIT_FUNCTION(user_streams); PHPAPI zend_result php_copy_file(const char *src, const char *dest); @@ -100,7 +101,8 @@ typedef struct { php_stream_context *default_context; HashTable *stream_wrappers; /* per-request copy of url_stream_wrappers_hash */ HashTable *stream_filters; /* per-request copy of stream_filters_hash */ - HashTable *wrapper_errors; /* key: wrapper address; value: linked list of char* */ + HashTable *wrapper_logged_errors; /* key: wrapper address; value: linked list of error entries */ + HashTable *wrapper_stored_errors; /* key: wrapper address; value: linked list of error entries */ int pclose_wait; #ifdef HAVE_GETHOSTBYNAME_R struct hostent tmp_host_info; diff --git a/main/php_streams.h b/main/php_streams.h index 1c52539cfcaee..33af6c3c91c30 100644 --- a/main/php_streams.h +++ b/main/php_streams.h @@ -248,6 +248,8 @@ struct _php_stream { #endif struct _php_stream *enclosing_stream; /* this is a private stream owned by enclosing_stream */ + + zend_llist *error_list; }; /* php_stream */ #define PHP_STREAM_CONTEXT(stream) \ @@ -539,6 +541,7 @@ PHPAPI ssize_t _php_stream_passthru(php_stream * src STREAMS_DC); #define php_stream_passthru(stream) _php_stream_passthru((stream) STREAMS_CC) END_EXTERN_C() +#include "streams/php_stream_errors.h" #include "streams/php_stream_transport.h" #include "streams/php_stream_plain_wrapper.h" #include "streams/php_stream_glob_wrapper.h" diff --git a/main/streams/php_stream_errors.h b/main/streams/php_stream_errors.h new file mode 100644 index 0000000000000..08998a87111cf --- /dev/null +++ b/main/streams/php_stream_errors.h @@ -0,0 +1,167 @@ +#ifndef PHP_STREAM_ERRORS_H +#define PHP_STREAM_ERRORS_H + +#include "php.h" +#include "php_streams.h" + +BEGIN_EXTERN_C() + +/* Error mode context options */ +#define PHP_STREAM_ERROR_MODE_ERROR 0 +#define PHP_STREAM_ERROR_MODE_EXCEPTION 1 +#define PHP_STREAM_ERROR_MODE_SILENT 2 + +/* Error store context options */ +#define PHP_STREAM_ERROR_STORE_AUTO 0 +#define PHP_STREAM_ERROR_STORE_NONE 1 +#define PHP_STREAM_ERROR_STORE_NON_TERM 2 +#define PHP_STREAM_ERROR_STORE_TERMINAL 3 +#define PHP_STREAM_ERROR_STORE_ALL 4 + +/* Error code definition for registration */ +typedef struct { + int code; + const char *name; +} php_stream_error_code_def; + +/* Stored error entry */ +typedef struct { + zend_string *message; + int code; + const char *wrapper_name; /* Points to wrapper->wops->label, no need to duplicate */ + const char *param; /* Points to passed string, caller manages lifetime for storage */ + int severity; + bool terminal; +} php_stream_error_entry; + +/* Sentinel for error code array termination */ +#define PHP_STREAM_ERROR_CODE_END {0, NULL} + +/* Error code registration */ +PHPAPI void php_stream_wrapper_register_error_codes( + php_stream_wrapper *wrapper, + const php_stream_error_code_def *codes +); + +PHPAPI const char *php_stream_wrapper_get_error_name( + php_stream_wrapper *wrapper, + int code +); + +/* Main error reporting functions */ +PHPAPI void php_stream_wrapper_error( + php_stream_wrapper *wrapper, + php_stream_context *context, + int options, + int severity, + bool terminal, + int code, + const char *fmt, + ... +) ZEND_ATTRIBUTE_FORMAT(printf, 7, 8); + +PHPAPI void php_stream_wrapper_error_param( + php_stream_wrapper *wrapper, + php_stream_context *context, + int options, + int severity, + bool terminal, + int code, + const char *param, + const char *fmt, + ... +) ZEND_ATTRIBUTE_FORMAT(printf, 8, 9); + +PHPAPI void php_stream_wrapper_error_param2( + php_stream_wrapper *wrapper, + php_stream_context *context, + int options, + int severity, + bool terminal, + int code, + const char *param1, + const char *param2, + const char *fmt, + ... +) ZEND_ATTRIBUTE_FORMAT(printf, 9, 10); + +PHPAPI void php_stream_error( + php_stream *stream, + int severity, + bool terminal, + int code, + const char *fmt, + ... +) ZEND_ATTRIBUTE_FORMAT(printf, 5, 6); + +/* Legacy wrapper error log - updated API */ +PHPAPI void php_stream_wrapper_log_error( + const php_stream_wrapper *wrapper, + int options, + int severity, + bool terminal, + int code, + const char *fmt, + ... +) ZEND_ATTRIBUTE_FORMAT(printf, 6, 7); + +PHPAPI void php_stream_wrapper_log_error_param( + const php_stream_wrapper *wrapper, + int options, + int severity, + bool terminal, + int code, + const char *param, + const char *fmt, + ... +) ZEND_ATTRIBUTE_FORMAT(printf, 7, 8); + +PHPAPI void php_stream_display_wrapper_errors( + php_stream_wrapper *wrapper, + const char *path, + const char *caption +); + +PHPAPI void php_stream_tidy_wrapper_error_log(php_stream_wrapper *wrapper); + +void php_stream_display_wrapper_errors(php_stream_wrapper *wrapper, const char *path, const char *caption); +void php_stream_tidy_wrapper_error_log(php_stream_wrapper *wrapper); + +/* Convenience macros */ +#define php_stream_wrapper_warn(wrapper, context, options, code, ...) \ + php_stream_wrapper_error(wrapper, context, options, E_WARNING, true, code, __VA_ARGS__) + +#define php_stream_wrapper_warn_nt(wrapper, context, options, code, ...) \ + php_stream_wrapper_error(wrapper, context, options, E_WARNING, false, code, __VA_ARGS__) + +#define php_stream_wrapper_notice(wrapper, context, options, code, ...) \ + php_stream_wrapper_error(wrapper, context, options, E_NOTICE, false, code, __VA_ARGS__) + +#define php_stream_wrapper_warn_param(wrapper, context, options, code, param, ...) \ + php_stream_wrapper_error_param(wrapper, context, options, E_WARNING, true, code, param, __VA_ARGS__) + +#define php_stream_warn(stream, code, ...) \ + php_stream_error(stream, E_WARNING, true, code, __VA_ARGS__) + +#define php_stream_warn_nt(stream, code, ...) \ + php_stream_error(stream, E_WARNING, false, code, __VA_ARGS__) + +#define php_stream_notice(stream, code, ...) \ + php_stream_error(stream, E_NOTICE, false, code, __VA_ARGS__) + +#define php_stream_fatal(stream, code, ...) \ + php_stream_error(stream, E_ERROR, true, code, __VA_ARGS__) + +/* Legacy log variants */ +#define php_stream_wrapper_log_warn(wrapper, options, code, ...) \ + php_stream_wrapper_log_error(wrapper, options, E_WARNING, true, code, __VA_ARGS__) + +#define php_stream_wrapper_log_warn_nt(wrapper, options, code, ...) \ + php_stream_wrapper_log_error(wrapper, options, E_WARNING, false, code, __VA_ARGS__) + +#define php_stream_wrapper_log_notice(wrapper, options, code, ...) \ + php_stream_wrapper_log_error(wrapper, options, E_NOTICE, false, code, __VA_ARGS__) + +END_EXTERN_C() + +#endif /* PHP_STREAM_ERRORS_H */ diff --git a/main/streams/stream_errors.c b/main/streams/stream_errors.c new file mode 100644 index 0000000000000..b308521ca33c3 --- /dev/null +++ b/main/streams/stream_errors.c @@ -0,0 +1,553 @@ +#include "php.h" +#include "php_globals.h" +#include "php_streams.h" +#include "php_stream_errors.h" +#include "stream_errors_arginfo.h" +#include "zend_exceptions.h" +#include "ext/standard/file.h" + +/* StreamException class entry */ +static zend_class_entry *php_ce_stream_exception; + +/* Error code registry */ +static HashTable *php_stream_wrapper_error_codes = NULL; + +static void php_stream_error_entry_dtor(void *error) +{ + php_stream_error_entry *entry = *(php_stream_error_entry **) error; + zend_string_release(entry->message); + efree(entry); +} + +static void php_stream_error_list_dtor(zval *item) +{ + zend_llist *list = (zend_llist *) Z_PTR_P(item); + zend_llist_destroy(list); + efree(list); +} + +/* Error code registration */ + +PHPAPI void php_stream_wrapper_register_error_codes( + php_stream_wrapper *wrapper, const php_stream_error_code_def *codes) +{ + if (!php_stream_wrapper_error_codes) { + php_stream_wrapper_error_codes = zend_new_array(8); + } + + zval code_table_zv, *code_table; + code_table = zend_hash_index_find(php_stream_wrapper_error_codes, (zend_ulong) wrapper); + + if (!code_table) { + code_table = &code_table_zv; + ZVAL_ARR(code_table, zend_new_array(8)); + zend_hash_index_update(php_stream_wrapper_error_codes, (zend_ulong) wrapper, code_table); + } + + for (const php_stream_error_code_def *def = codes; def->name != NULL; def++) { + zend_string *name = zend_string_init(def->name, strlen(def->name), 1); + zval zv; + ZVAL_STR(&zv, name); + zend_hash_index_update(code_table, def->code, &zv); + } +} + +PHPAPI const char *php_stream_wrapper_get_error_name(php_stream_wrapper *wrapper, int code) +{ + if (!php_stream_wrapper_error_codes) { + return NULL; + } + + zval *code_table = zend_hash_index_find(php_stream_wrapper_error_codes, (zend_ulong) wrapper); + + if (!code_table) { + return NULL; + } + + zval *error_name = zend_hash_index_find(Z_ARR_P(code_table), code); + return error_name ? Z_STRVAL_P(error_name) : NULL; +} + +/* Context option helpers */ + +static int php_stream_auto_decide_error_store_mode(int error_mode) +{ + switch (error_mode) { + case PHP_STREAM_ERROR_MODE_ERROR: + return PHP_STREAM_ERROR_STORE_NONE; + case PHP_STREAM_ERROR_MODE_EXCEPTION: + return PHP_STREAM_ERROR_STORE_NON_TERM; + case PHP_STREAM_ERROR_MODE_SILENT: + return PHP_STREAM_ERROR_STORE_ALL; + default: + return PHP_STREAM_ERROR_STORE_NONE; + } +} + +static int php_stream_get_error_mode(php_stream_context *context) +{ + if (!context) { + return PHP_STREAM_ERROR_MODE_ERROR; + } + + zval *option = php_stream_context_get_option(context, "stream", "error_mode"); + if (option && Z_TYPE_P(option) == IS_LONG) { + return Z_LVAL_P(option); + } + + return PHP_STREAM_ERROR_MODE_ERROR; +} + +static int php_stream_get_error_store_mode(php_stream_context *context, int error_mode) +{ + if (!context) { + return php_stream_auto_decide_error_store_mode(error_mode); + } + + zval *option = php_stream_context_get_option(context, "stream", "error_store"); + if (option && Z_TYPE_P(option) == IS_LONG) { + int store_mode = Z_LVAL_P(option); + + if (store_mode == PHP_STREAM_ERROR_STORE_AUTO) { + return php_stream_auto_decide_error_store_mode(error_mode); + } + + return store_mode; + } + + return php_stream_auto_decide_error_store_mode(error_mode); +} + +static bool php_stream_should_store_error(int store_mode, bool terminal) +{ + switch (store_mode) { + case PHP_STREAM_ERROR_STORE_NONE: + return false; + case PHP_STREAM_ERROR_STORE_NON_TERM: + return !terminal; + case PHP_STREAM_ERROR_STORE_TERMINAL: + return terminal; + case PHP_STREAM_ERROR_STORE_ALL: + return true; + default: + return false; + } +} + +/* StreamException methods */ + +static void php_stream_throw_exception( + const char *message, int code, const char *wrapper_name, const char *param) +{ + zval ex; + + object_init_ex(&ex, php_ce_stream_exception); + + zend_update_property_string(php_ce_stream_exception, Z_OBJ(ex), ZEND_STRL("message"), message); + zend_update_property_long(php_ce_stream_exception, Z_OBJ(ex), ZEND_STRL("code"), code); + zend_update_property_string( + php_ce_stream_exception, Z_OBJ(ex), ZEND_STRL("wrapperName"), wrapper_name); + + if (param) { + zend_update_property_string(php_ce_stream_exception, Z_OBJ(ex), ZEND_STRL("param"), param); + } + + zend_throw_exception_object(&ex); +} + +/* Core error processing */ + +static void php_stream_process_error(php_stream_context *context, const char *wrapper_name, + php_stream *stream, int code, const char *message, const char *param, int severity, + bool terminal) +{ + int error_mode = php_stream_get_error_mode(context); + + /* Handle error based on error_mode */ + switch (error_mode) { + case PHP_STREAM_ERROR_MODE_ERROR: + if (param) { + php_error_docref1(NULL, param, severity, "%s", message); + } else { + php_error_docref(NULL, severity, "%s", message); + } + break; + + case PHP_STREAM_ERROR_MODE_EXCEPTION: + if (terminal) { + php_stream_throw_exception(message, code, wrapper_name, param); + } + break; + + case PHP_STREAM_ERROR_MODE_SILENT: + break; + } + + /* Call user error handler if set */ + if (context) { + zval *handler = php_stream_context_get_option(context, "stream", "error_handler"); + if (handler && Z_TYPE_P(handler) == IS_CALLABLE) { + zval retval; + zval args[5]; + + /* Arg 0: wrapper name */ + ZVAL_STRING(&args[0], wrapper_name); + + /* Arg 1: stream resource or null */ + if (stream && stream->res) { + ZVAL_RES(&args[1], stream->res); + GC_ADDREF(stream->res); + } else { + ZVAL_NULL(&args[1]); + } + + /* Arg 2: error code */ + ZVAL_LONG(&args[2], code); + + /* Arg 3: message */ + ZVAL_STRING(&args[3], message); + + /* Arg 4: param (or null) */ + if (param) { + ZVAL_STRING(&args[4], param); + } else { + ZVAL_NULL(&args[4]); + } + + call_user_function(NULL, NULL, handler, &retval, 5, args); + + zval_ptr_dtor(&retval); + zval_ptr_dtor(&args[0]); + zval_ptr_dtor(&args[1]); + zval_ptr_dtor(&args[3]); + zval_ptr_dtor(&args[4]); + } + } +} + +/* Helper to create error entry */ +static php_stream_error_entry *php_stream_create_error_entry(zend_string *message, int code, + const char *wrapper_name, const char *param, int severity, bool terminal) +{ + php_stream_error_entry *entry = emalloc(sizeof(php_stream_error_entry)); + entry->message = message; /* Takes ownership */ + entry->code = code; + entry->wrapper_name = wrapper_name; + entry->param = param; + entry->severity = severity; + entry->terminal = terminal; + return entry; +} + +/* Common storage function*/ +static void php_stream_store_error_common(php_stream_context *context, php_stream *stream, + php_stream_wrapper *wrapper, zend_string *message, int code, const char *wrapper_name, + const char *param, int severity, bool terminal) +{ + int error_mode = php_stream_get_error_mode(context); + int store_mode = php_stream_get_error_store_mode(context, error_mode); + + if (!php_stream_should_store_error(store_mode, terminal)) { + return; + } + + php_stream_error_entry *entry + = php_stream_create_error_entry(message, code, wrapper_name, param, severity, terminal); + zend_string_addref(message); /* Storage keeps a reference */ + + zend_llist *list; + + if (stream) { + /* Store in stream's error list */ + if (!stream->error_list) { + stream->error_list = emalloc(sizeof(zend_llist)); + zend_llist_init(stream->error_list, sizeof(php_stream_error_entry *), + php_stream_error_entry_dtor, 0); + } + list = stream->error_list; + } else { + /* Store in FG(stream_errors) for wrapper errors */ + if (!FG(wrapper_stored_errors)) { + ALLOC_HASHTABLE(FG(wrapper_stored_errors)); + zend_hash_init(FG(wrapper_stored_errors), 8, NULL, php_stream_error_list_dtor, 0); + list = NULL; + } else { + list = zend_hash_str_find_ptr( + FG(wrapper_stored_errors), (const char *) &wrapper, sizeof(wrapper)); + } + + if (!list) { + zend_llist new_list; + zend_llist_init( + &new_list, sizeof(php_stream_error_entry *), php_stream_error_entry_dtor, 0); + list = zend_hash_str_update_mem(FG(wrapper_stored_errors), (const char *) &wrapper, + sizeof(wrapper), &new_list, sizeof(new_list)); + } + } + + zend_llist_add_element(list, &entry); +} + +/* Wrapper error reporting - stores in FG(wrapper_stored_errors) */ + +static void php_stream_wrapper_error_internal(php_stream_wrapper *wrapper, + php_stream_context *context, int options, int severity, bool terminal, int code, + const char *param, const char *fmt, va_list args) +{ + zend_string *message = vstrpprintf(0, fmt, args); + const char *wrapper_name = wrapper ? wrapper->wops->label : "unknown"; + + if (options & REPORT_ERRORS) { + php_stream_process_error( + context, wrapper_name, NULL, code, ZSTR_VAL(message), param, severity, terminal); + } + + php_stream_store_error_common( + context, NULL, wrapper, message, code, wrapper_name, param, severity, terminal); + + zend_string_release(message); +} + +PHPAPI void php_stream_wrapper_error(php_stream_wrapper *wrapper, php_stream_context *context, + int options, int severity, bool terminal, int code, const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + php_stream_wrapper_error_internal( + wrapper, context, options, severity, terminal, code, NULL, fmt, args); + va_end(args); +} + +PHPAPI void php_stream_wrapper_error_param(php_stream_wrapper *wrapper, php_stream_context *context, + int options, int severity, bool terminal, int code, const char *param, const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + php_stream_wrapper_error_internal( + wrapper, context, options, severity, terminal, code, param, fmt, args); + va_end(args); +} + +PHPAPI void php_stream_wrapper_error_param2(php_stream_wrapper *wrapper, + php_stream_context *context, int options, int severity, bool terminal, int code, + const char *param1, const char *param2, const char *fmt, ...) +{ + char *combined_param; + spprintf(&combined_param, 0, "%s,%s", param1, param2); + + va_list args; + va_start(args, fmt); + php_stream_wrapper_error_internal( + wrapper, context, options, severity, terminal, code, combined_param, fmt, args); + va_end(args); + + efree(combined_param); +} + +/* Wrapper error logging - stores in FG(wrapper_logged_errors) */ + +static void php_stream_wrapper_log_store_error(const php_stream_wrapper *wrapper, + zend_string *message, int code, const char *wrapper_name, const char *param, int severity, + bool terminal) +{ + php_stream_error_entry *entry + = php_stream_create_error_entry(message, code, wrapper_name, param, severity, terminal); + zend_string_addref(message); + + if (!FG(wrapper_logged_errors)) { + ALLOC_HASHTABLE(FG(wrapper_logged_errors)); + zend_hash_init(FG(wrapper_logged_errors), 8, NULL, php_stream_error_list_dtor, 0); + } + + zend_llist *list = zend_hash_str_find_ptr( + FG(wrapper_logged_errors), (const char *) &wrapper, sizeof(wrapper)); + + if (!list) { + zend_llist new_list; + zend_llist_init( + &new_list, sizeof(php_stream_error_entry *), php_stream_error_entry_dtor, 0); + list = zend_hash_str_update_mem(FG(wrapper_logged_errors), (const char *) &wrapper, + sizeof(wrapper), &new_list, sizeof(new_list)); + } + + zend_llist_add_element(list, &entry); +} + +static void php_stream_wrapper_log_error_internal(const php_stream_wrapper *wrapper, int options, + int severity, bool terminal, int code, const char *param, va_list args) +{ + zend_string *message = vstrpprintf(0, args, args); + const char *wrapper_name = wrapper ? wrapper->wops->label : "unknown"; + + if (options & REPORT_ERRORS) { + /* Report immediately using standard error functions */ + if (param) { + php_error_docref1(NULL, param, severity, "%s", ZSTR_VAL(message)); + } else { + php_error_docref(NULL, severity, "%s", ZSTR_VAL(message)); + } + zend_string_release(message); + } else { + /* Store for later display in FG(wrapper_logged_errors) */ + php_stream_wrapper_log_store_error( + wrapper, message, code, wrapper_name, param, severity, terminal); + zend_string_release(message); + } +} + +PHPAPI void php_stream_wrapper_log_error(const php_stream_wrapper *wrapper, int options, + int severity, bool terminal, int code, const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + php_stream_wrapper_log_error_internal(wrapper, options, severity, terminal, code, NULL, args); + va_end(args); +} + +PHPAPI void php_stream_wrapper_log_error_param(const php_stream_wrapper *wrapper, int options, + int severity, bool terminal, int code, const char *param, const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + php_stream_wrapper_log_error_internal(wrapper, options, severity, terminal, code, param, args); + va_end(args); +} + +static zend_llist *php_stream_get_wrapper_errors_list(php_stream_wrapper *wrapper) +{ + if (!FG(wrapper_logged_errors)) { + return NULL; + } else { + return (zend_llist*) zend_hash_str_find_ptr(FG(wrapper_logged_errors), (const char*)&wrapper, sizeof(wrapper)); + } +} + +/* {{{ wrapper error reporting */ +static void php_stream_display_wrapper_errors(php_stream_wrapper *wrapper, const char *path, const char *caption) +{ + char *tmp; + char *msg; + char errstr[256]; + int free_msg = 0; + + if (EG(exception)) { + /* Don't emit additional warnings if an exception has already been thrown. */ + return; + } + + tmp = estrdup(path); + if (wrapper) { + zend_llist *err_list = php_stream_get_wrapper_errors_list(wrapper); + if (err_list) { + size_t l = 0; + int brlen; + int i; + int count = (int) zend_llist_count(err_list); + const char *br; + php_stream_error_entry **err_entry_p; + zend_llist_position pos; + + if (PG(html_errors)) { + brlen = 7; + br = "
\n"; + } else { + brlen = 1; + br = "\n"; + } + + for (err_entry_p = zend_llist_get_first_ex(err_list, &pos), i = 0; err_entry_p; + err_entry_p = zend_llist_get_next_ex(err_list, &pos), i++) { + strcat(msg, ZSTR_VAL((*err_entry_p)->message)); + if (i < count - 1) { + l += brlen; + } + } + msg = emalloc(l + 1); + msg[0] = '\0'; + for (err_entry_p = zend_llist_get_first_ex(err_list, &pos), i = 0; err_entry_p; + err_entry_p = zend_llist_get_next_ex(err_list, &pos), i++) { + strcat(msg, ZSTR_VAL((*err_entry_p)->message)); + if (i < count - 1) { + strcat(msg, br); + } + } + + free_msg = 1; + } else { + if (wrapper == &php_plain_files_wrapper) { + msg = php_socket_strerror_s(errno, errstr, sizeof(errstr)); + } else { + msg = "operation failed"; + } + } + } else { + msg = "no suitable wrapper could be found"; + } + + php_strip_url_passwd(tmp); + php_error_docref1(NULL, tmp, E_WARNING, "%s: %s", caption, msg); + efree(tmp); + if (free_msg) { + efree(msg); + } +} + +void php_stream_tidy_wrapper_error_log(php_stream_wrapper *wrapper) +{ + if (wrapper && FG(wrapper_logged_errors)) { + zend_hash_str_del(FG(wrapper_logged_errors), (const char *) &wrapper, sizeof(wrapper)); + } +} + +/* Stream error reporting */ + +PHPAPI void php_stream_error( + php_stream *stream, int severity, bool terminal, int code, const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + zend_string *message = vstrpprintf(0, fmt, args); + va_end(args); + + php_stream_wrapper *wrapper = stream->wrapper; + const char *wrapper_name = wrapper ? wrapper->wops->label : "stream"; + + php_stream_context *context = PHP_STREAM_CONTEXT(stream); + + /* Process the error - always report for stream errors */ + php_stream_process_error( + context, wrapper_name, stream, code, ZSTR_VAL(message), NULL, severity, terminal); + + /* Store error */ + php_stream_store_error_common( + context, stream, wrapper, message, code, wrapper_name, NULL, severity, terminal); + + zend_string_release(message); +} + +/* StreamException class registration */ + +PHP_MINIT_FUNCTION(stream_errors) +{ + php_ce_stream_exception = register_class_StreamException(zend_ce_exception); + + return SUCCESS; +} + +PHP_METHOD(StreamException, getParam) +{ + ZEND_PARSE_PARAMETERS_NONE(); + + zval *param = zend_read_property( + php_ce_stream_exception, Z_OBJ_P(getThis()), ZEND_STRL("param"), 1, NULL); + RETURN_COPY(param); +} + +PHP_METHOD(StreamException, getWrapperName) +{ + ZEND_PARSE_PARAMETERS_NONE(); + + zval *wrapper_name = zend_read_property( + php_ce_stream_exception, Z_OBJ_P(getThis()), ZEND_STRL("wrapperName"), 1, NULL); + RETURN_COPY(wrapper_name); +} diff --git a/main/streams/stream_errors.stub.php b/main/streams/stream_errors.stub.php new file mode 100644 index 0000000000000..387c2c692703f --- /dev/null +++ b/main/streams/stream_errors.stub.php @@ -0,0 +1,16 @@ +\n"; - } else { - brlen = 1; - br = "\n"; - } - - for (err_buf_p = zend_llist_get_first_ex(err_list, &pos), i = 0; - err_buf_p; - err_buf_p = zend_llist_get_next_ex(err_list, &pos), i++) { - l += strlen(*err_buf_p); - if (i < count - 1) { - l += brlen; - } - } - msg = emalloc(l + 1); - msg[0] = '\0'; - for (err_buf_p = zend_llist_get_first_ex(err_list, &pos), i = 0; - err_buf_p; - err_buf_p = zend_llist_get_next_ex(err_list, &pos), i++) { - strcat(msg, *err_buf_p); - if (i < count - 1) { - strcat(msg, br); - } - } - - free_msg = 1; - } else { - if (wrapper == &php_plain_files_wrapper) { - msg = php_socket_strerror_s(errno, errstr, sizeof(errstr)); - } else { - msg = "operation failed"; - } - } - } else { - msg = "no suitable wrapper could be found"; - } - - php_strip_url_passwd(tmp); - php_error_docref1(NULL, tmp, E_WARNING, "%s: %s", caption, msg); - efree(tmp); - if (free_msg) { - efree(msg); - } -} - -static void php_stream_tidy_wrapper_error_log(php_stream_wrapper *wrapper) -{ - if (wrapper && FG(wrapper_errors)) { - zend_hash_str_del(FG(wrapper_errors), (const char*)&wrapper, sizeof(wrapper)); - } -} - -static void wrapper_error_dtor(void *error) -{ - efree(*(char**)error); -} - -static void wrapper_list_dtor(zval *item) { - zend_llist *list = (zend_llist*)Z_PTR_P(item); - zend_llist_destroy(list); - efree(list); -} - -PHPAPI void php_stream_wrapper_log_error(const php_stream_wrapper *wrapper, int options, const char *fmt, ...) -{ - va_list args; - char *buffer = NULL; - - va_start(args, fmt); - vspprintf(&buffer, 0, fmt, args); - va_end(args); - - if ((options & REPORT_ERRORS) || wrapper == NULL) { - php_error_docref(NULL, E_WARNING, "%s", buffer); - efree(buffer); - } else { - zend_llist *list = NULL; - if (!FG(wrapper_errors)) { - ALLOC_HASHTABLE(FG(wrapper_errors)); - zend_hash_init(FG(wrapper_errors), 8, NULL, wrapper_list_dtor, 0); - } else { - list = zend_hash_str_find_ptr(FG(wrapper_errors), (const char*)&wrapper, sizeof(wrapper)); - } - - if (!list) { - zend_llist new_list; - zend_llist_init(&new_list, sizeof(buffer), wrapper_error_dtor, 0); - list = zend_hash_str_update_mem(FG(wrapper_errors), (const char*)&wrapper, - sizeof(wrapper), &new_list, sizeof(new_list)); - } - - /* append to linked list */ - zend_llist_add_element(list, &buffer); - } -} - - /* }}} */ /* allocate a new stream for a particular ops */ @@ -1878,10 +1743,16 @@ void php_shutdown_stream_hashes(void) FG(stream_filters) = NULL; } - if (FG(wrapper_errors)) { - zend_hash_destroy(FG(wrapper_errors)); - efree(FG(wrapper_errors)); - FG(wrapper_errors) = NULL; + if (FG(wrapper_logged_errors)) { + zend_hash_destroy(FG(wrapper_logged_errors)); + efree(FG(wrapper_logged_errors)); + FG(wrapper_logged_errors) = NULL; + } + + if (FG(wrapper_stored_errors)) { + zend_hash_destroy(FG(wrapper_stored_errors)); + efree(FG(wrapper_stored_errors)); + FG(wrapper_stored_errors) = NULL; } } diff --git a/win32/build/config.w32 b/win32/build/config.w32 index aefcfb5f82474..6cd6907f28250 100644 --- a/win32/build/config.w32 +++ b/win32/build/config.w32 @@ -298,7 +298,7 @@ AC_DEFINE('HAVE_STRNLEN', 1); AC_DEFINE('ZEND_CHECK_STACK_LIMIT', 1) -ADD_SOURCES("main/streams", "streams.c cast.c memory.c filter.c plain_wrapper.c \ +ADD_SOURCES("main/streams", "streams.c stream_errors.c cast.c memory.c filter.c plain_wrapper.c \ userspace.c transports.c xp_socket.c mmap.c glob_wrapper.c"); ADD_FLAG("CFLAGS_BD_MAIN_STREAMS", "/D ZEND_ENABLE_STATIC_TSRMLS_CACHE=1"); From 435338d3a3380ac46b20b2be7c15fc84b9e3888c Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Sun, 16 Nov 2025 15:53:30 +0100 Subject: [PATCH 02/68] stream: add error codes and handler check --- main/php_streams.h | 4 - main/streams/php_stream_errors.h | 105 ++++++++-- main/streams/stream_errors.c | 76 +++---- main/streams/stream_errors.stub.php | 294 ++++++++++++++++++++++++++- main/streams/stream_errors_arginfo.h | 71 ++++++- 5 files changed, 472 insertions(+), 78 deletions(-) diff --git a/main/php_streams.h b/main/php_streams.h index 33af6c3c91c30..601223bd9a5fd 100644 --- a/main/php_streams.h +++ b/main/php_streams.h @@ -645,10 +645,6 @@ PHPAPI const char *php_stream_locate_eol(php_stream *stream, zend_string *buf); #define php_stream_open_wrapper(path, mode, options, opened) _php_stream_open_wrapper_ex((path), (mode), (options), (opened), NULL STREAMS_CC) #define php_stream_open_wrapper_ex(path, mode, options, opened, context) _php_stream_open_wrapper_ex((path), (mode), (options), (opened), (context) STREAMS_CC) - -/* pushes an error message onto the stack for a wrapper instance */ -PHPAPI void php_stream_wrapper_log_error(const php_stream_wrapper *wrapper, int options, const char *fmt, ...) PHP_ATTRIBUTE_FORMAT(printf, 3, 4); - typedef enum { PHP_STREAM_UNCHANGED = 0, /* orig stream was seekable anyway */ PHP_STREAM_RELEASED = 1, /* newstream should be used; origstream is no longer valid */ diff --git a/main/streams/php_stream_errors.h b/main/streams/php_stream_errors.h index 08998a87111cf..5331000dfe149 100644 --- a/main/streams/php_stream_errors.h +++ b/main/streams/php_stream_errors.h @@ -1,3 +1,19 @@ +/* + +----------------------------------------------------------------------+ + | Copyright (c) The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | https://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Jakub Zelenka | + +----------------------------------------------------------------------+ + */ + #ifndef PHP_STREAM_ERRORS_H #define PHP_STREAM_ERRORS_H @@ -18,11 +34,76 @@ BEGIN_EXTERN_C() #define PHP_STREAM_ERROR_STORE_TERMINAL 3 #define PHP_STREAM_ERROR_STORE_ALL 4 -/* Error code definition for registration */ -typedef struct { - int code; - const char *name; -} php_stream_error_code_def; +/* Stream Error Codes*/ +/* No error */ +#define STREAM_ERROR_CODE_NONE 0 +/* Generic unspecified error */ +#define STREAM_ERROR_CODE_GENERIC 1 +/* Stream I/O operations */ +#define STREAM_ERROR_CODE_READ_FAILED 10 +#define STREAM_ERROR_CODE_WRITE_FAILED 11 +#define STREAM_ERROR_CODE_SEEK_FAILED 12 +#define STREAM_ERROR_CODE_SEEK_NOT_SUPPORTED 13 +#define STREAM_ERROR_CODE_FLUSH_FAILED 14 +#define STREAM_ERROR_CODE_TRUNCATE_FAILED 15 +#define STREAM_ERROR_CODE_NOT_WRITABLE 16 +#define STREAM_ERROR_CODE_NOT_READABLE 17 +/* File system operations */ +#define STREAM_ERROR_CODE_NOT_FOUND 30 +#define STREAM_ERROR_CODE_PERMISSION_DENIED 31 +#define STREAM_ERROR_CODE_ALREADY_EXISTS 32 +#define STREAM_ERROR_CODE_INVALID_PATH 33 +#define STREAM_ERROR_CODE_PATH_TOO_LONG 34 +#define STREAM_ERROR_CODE_UNLINK_FAILED 35 +#define STREAM_ERROR_CODE_RENAME_FAILED 36 +#define STREAM_ERROR_CODE_MKDIR_FAILED 37 +#define STREAM_ERROR_CODE_RMDIR_FAILED 38 +#define STREAM_ERROR_CODE_STAT_FAILED 39 +#define STREAM_ERROR_CODE_CHMOD_FAILED 40 +#define STREAM_ERROR_CODE_CHOWN_FAILED 41 +#define STREAM_ERROR_CODE_TOUCH_FAILED 42 +#define STREAM_ERROR_CODE_INVALID_MODE 43 +#define STREAM_ERROR_CODE_MODE_NOT_SUPPORTED 44 +#define STREAM_ERROR_CODE_READONLY 45 +#define STREAM_ERROR_CODE_RECURSION_DETECTED 46 +/* Wrapper/protocol operations */ +#define STREAM_ERROR_CODE_WRAPPER_NOT_FOUND 60 +#define STREAM_ERROR_CODE_WRAPPER_DISABLED 61 +#define STREAM_ERROR_CODE_PROTOCOL_UNSUPPORTED 62 +#define STREAM_ERROR_CODE_WRAPPER_REGISTRATION_FAILED 63 +#define STREAM_ERROR_CODE_WRAPPER_UNREGISTRATION_FAILED 64 +#define STREAM_ERROR_CODE_WRAPPER_RESTORATION_FAILED 65 +/* Filter operations */ +#define STREAM_ERROR_CODE_FILTER_NOT_FOUND 80 +#define STREAM_ERROR_CODE_FILTER_FAILED 81 +/* Cast/conversion operations */ +#define STREAM_ERROR_CODE_CAST_FAILED 90 +#define STREAM_ERROR_CODE_CAST_NOT_SUPPORTED 91 +#define STREAM_ERROR_CODE_MAKE_SEEKABLE_FAILED 92 +#define STREAM_ERROR_CODE_BUFFERED_DATA_LOST 93 +/* Network/socket operations */ +#define STREAM_ERROR_CODE_NETWORK_SEND_FAILED 100 +#define STREAM_ERROR_CODE_NETWORK_RECV_FAILED 101 +#define STREAM_ERROR_CODE_SSL_NOT_SUPPORTED 102 +#define STREAM_ERROR_CODE_SOCKET_PATH_TOO_LONG 103 +#define STREAM_ERROR_CODE_OOB_NOT_SUPPORTED 104 +#define STREAM_ERROR_CODE_PROTOCOL_ERROR 105 +#define STREAM_ERROR_CODE_INVALID_URL 106 +#define STREAM_ERROR_CODE_INVALID_RESPONSE 107 +#define STREAM_ERROR_CODE_REDIRECT_LIMIT 108 +#define STREAM_ERROR_CODE_AUTH_FAILED 109 +/* Encoding/decoding operations */ +#define STREAM_ERROR_CODE_ENCODING_FAILED 120 +#define STREAM_ERROR_CODE_INVALID_FORMAT 121 +/* Resource/allocation operations */ +#define STREAM_ERROR_CODE_ALLOCATION_FAILED 130 +#define STREAM_ERROR_CODE_TEMPORARY_FILE_FAILED 131 +/* Locking operations */ +#define STREAM_ERROR_CODE_LOCK_FAILED 140 +#define STREAM_ERROR_CODE_LOCK_NOT_SUPPORTED 141 +/* Userspace stream operations */ +#define STREAM_ERROR_CODE_USERSPACE_NOT_IMPLEMENTED 150 +#define STREAM_ERROR_CODE_USERSPACE_INVALID_RETURN 151 /* Stored error entry */ typedef struct { @@ -34,20 +115,6 @@ typedef struct { bool terminal; } php_stream_error_entry; -/* Sentinel for error code array termination */ -#define PHP_STREAM_ERROR_CODE_END {0, NULL} - -/* Error code registration */ -PHPAPI void php_stream_wrapper_register_error_codes( - php_stream_wrapper *wrapper, - const php_stream_error_code_def *codes -); - -PHPAPI const char *php_stream_wrapper_get_error_name( - php_stream_wrapper *wrapper, - int code -); - /* Main error reporting functions */ PHPAPI void php_stream_wrapper_error( php_stream_wrapper *wrapper, diff --git a/main/streams/stream_errors.c b/main/streams/stream_errors.c index b308521ca33c3..52428e9065f34 100644 --- a/main/streams/stream_errors.c +++ b/main/streams/stream_errors.c @@ -1,3 +1,19 @@ +/* + +----------------------------------------------------------------------+ + | Copyright (c) The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | https://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Jakub Zelenka | + +----------------------------------------------------------------------+ + */ + #include "php.h" #include "php_globals.h" #include "php_streams.h" @@ -26,48 +42,6 @@ static void php_stream_error_list_dtor(zval *item) efree(list); } -/* Error code registration */ - -PHPAPI void php_stream_wrapper_register_error_codes( - php_stream_wrapper *wrapper, const php_stream_error_code_def *codes) -{ - if (!php_stream_wrapper_error_codes) { - php_stream_wrapper_error_codes = zend_new_array(8); - } - - zval code_table_zv, *code_table; - code_table = zend_hash_index_find(php_stream_wrapper_error_codes, (zend_ulong) wrapper); - - if (!code_table) { - code_table = &code_table_zv; - ZVAL_ARR(code_table, zend_new_array(8)); - zend_hash_index_update(php_stream_wrapper_error_codes, (zend_ulong) wrapper, code_table); - } - - for (const php_stream_error_code_def *def = codes; def->name != NULL; def++) { - zend_string *name = zend_string_init(def->name, strlen(def->name), 1); - zval zv; - ZVAL_STR(&zv, name); - zend_hash_index_update(code_table, def->code, &zv); - } -} - -PHPAPI const char *php_stream_wrapper_get_error_name(php_stream_wrapper *wrapper, int code) -{ - if (!php_stream_wrapper_error_codes) { - return NULL; - } - - zval *code_table = zend_hash_index_find(php_stream_wrapper_error_codes, (zend_ulong) wrapper); - - if (!code_table) { - return NULL; - } - - zval *error_name = zend_hash_index_find(Z_ARR_P(code_table), code); - return error_name ? Z_STRVAL_P(error_name) : NULL; -} - /* Context option helpers */ static int php_stream_auto_decide_error_store_mode(int error_mode) @@ -186,10 +160,22 @@ static void php_stream_process_error(php_stream_context *context, const char *wr /* Call user error handler if set */ if (context) { zval *handler = php_stream_context_get_option(context, "stream", "error_handler"); - if (handler && Z_TYPE_P(handler) == IS_CALLABLE) { + if (handler) { + zend_fcall_info_cache fcc; + char *is_callable_error = NULL; zval retval; zval args[5]; + if (!zend_is_callable_ex(handler, NULL, 0, NULL, &fcc, &is_callable_error)) { + if (is_callable_error) { + zend_type_error("stream error handler must be a valid callback, %s", is_callable_error); + efree(is_callable_error); + } else { + zend_type_error("stream error must be a valid callback"); + } + return; + } + /* Arg 0: wrapper name */ ZVAL_STRING(&args[0], wrapper_name); @@ -525,10 +511,12 @@ PHPAPI void php_stream_error( zend_string_release(message); } -/* StreamException class registration */ +/* StreamException class and error constants registration */ PHP_MINIT_FUNCTION(stream_errors) { + register_stream_errors_symbols(module_number); + php_ce_stream_exception = register_class_StreamException(zend_ce_exception); return SUCCESS; diff --git a/main/streams/stream_errors.stub.php b/main/streams/stream_errors.stub.php index 387c2c692703f..fb660ad6e56c5 100644 --- a/main/streams/stream_errors.stub.php +++ b/main/streams/stream_errors.stub.php @@ -1,16 +1,298 @@ Date: Sun, 16 Nov 2025 16:46:12 +0100 Subject: [PATCH 03/68] stream: convert phar errors --- ext/phar/dirstream.c | 92 ++++++++++++++++++++++--------- ext/phar/stream.c | 128 +++++++++++++++++++++++++++++-------------- 2 files changed, 152 insertions(+), 68 deletions(-) diff --git a/ext/phar/dirstream.c b/ext/phar/dirstream.c index f37599e7db117..7faeddba25d7d 100644 --- a/ext/phar/dirstream.c +++ b/ext/phar/dirstream.c @@ -254,25 +254,30 @@ php_stream *phar_wrapper_open_dir(php_stream_wrapper *wrapper, const char *path, phar_archive_data *phar; if ((resource = phar_parse_url(wrapper, path, mode, options)) == NULL) { - php_stream_wrapper_log_error(wrapper, options, "phar url \"%s\" is unknown", path); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_INVALID_URL, + "phar url \"%s\" is unknown", path); return NULL; } /* we must have at the very least phar://alias.phar/ */ if (!resource->scheme || !resource->host || !resource->path) { if (resource->host && !resource->path) { - php_stream_wrapper_log_error(wrapper, options, "phar error: no directory in \"%s\", must have at least phar://%s/ for root directory (always use full path to a new phar)", path, ZSTR_VAL(resource->host)); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_INVALID_PATH, + "phar error: no directory in \"%s\", must have at least phar://%s/ for root directory (always use full path to a new phar)", + path, ZSTR_VAL(resource->host)); php_url_free(resource); return NULL; } php_url_free(resource); - php_stream_wrapper_log_error(wrapper, options, "phar error: invalid url \"%s\", must have at least phar://%s/", path, path); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_INVALID_URL, + "phar error: invalid url \"%s\", must have at least phar://%s/", path, path); return NULL; } if (!zend_string_equals_literal_ci(resource->scheme, "phar")) { php_url_free(resource); - php_stream_wrapper_log_error(wrapper, options, "phar error: not a phar url \"%s\"", path); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_PROTOCOL_UNSUPPORTED, + "phar error: not a phar url \"%s\"", path); return NULL; } @@ -280,10 +285,11 @@ php_stream *phar_wrapper_open_dir(php_stream_wrapper *wrapper, const char *path, if (FAILURE == phar_get_archive(&phar, ZSTR_VAL(resource->host), ZSTR_LEN(resource->host), NULL, 0, &error)) { if (error) { - php_stream_wrapper_log_error(wrapper, options, "%s", error); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_NOT_FOUND, "%s", error); efree(error); } else { - php_stream_wrapper_log_error(wrapper, options, "phar file \"%s\" is unknown", ZSTR_VAL(resource->host)); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_NOT_FOUND, + "phar file \"%s\" is unknown", ZSTR_VAL(resource->host)); } php_url_free(resource); return NULL; @@ -353,7 +359,8 @@ int phar_wrapper_mkdir(php_stream_wrapper *wrapper, const char *url_from, int mo /* pre-readonly check, we need to know if this is a data phar */ if (FAILURE == phar_split_fname(url_from, strlen(url_from), &arch, &arch_len, NULL, NULL, 2, 2)) { - php_stream_wrapper_log_error(wrapper, options, "phar error: cannot create directory \"%s\", no phar archive specified", url_from); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_NOT_FOUND, + "phar error: cannot create directory \"%s\", no phar archive specified", url_from); return 0; } @@ -364,7 +371,8 @@ int phar_wrapper_mkdir(php_stream_wrapper *wrapper, const char *url_from, int mo efree(arch); if (PHAR_G(readonly) && (!phar || !phar->is_data)) { - php_stream_wrapper_log_error(wrapper, options, "phar error: cannot create directory \"%s\", write operations disabled", url_from); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_READONLY, + "phar error: cannot create directory \"%s\", write operations disabled", url_from); return 0; } @@ -375,18 +383,22 @@ int phar_wrapper_mkdir(php_stream_wrapper *wrapper, const char *url_from, int mo /* we must have at the very least phar://alias.phar/internalfile.php */ if (!resource->scheme || !resource->host || !resource->path) { php_url_free(resource); - php_stream_wrapper_log_error(wrapper, options, "phar error: invalid url \"%s\"", url_from); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_INVALID_URL, + "phar error: invalid url \"%s\"", url_from); return 0; } if (!zend_string_equals_literal_ci(resource->scheme, "phar")) { php_url_free(resource); - php_stream_wrapper_log_error(wrapper, options, "phar error: not a phar stream url \"%s\"", url_from); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_PROTOCOL_UNSUPPORTED, + "phar error: not a phar stream url \"%s\"", url_from); return 0; } if (FAILURE == phar_get_archive(&phar, ZSTR_VAL(resource->host), ZSTR_LEN(resource->host), NULL, 0, &error)) { - php_stream_wrapper_log_error(wrapper, options, "phar error: cannot create directory \"%s\" in phar \"%s\", error retrieving phar information: %s", ZSTR_VAL(resource->path) + 1, ZSTR_VAL(resource->host), error); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_MKDIR_FAILED, + "phar error: cannot create directory \"%s\" in phar \"%s\", error retrieving phar information: %s", + ZSTR_VAL(resource->path) + 1, ZSTR_VAL(resource->host), error); efree(error); php_url_free(resource); return 0; @@ -398,13 +410,17 @@ int phar_wrapper_mkdir(php_stream_wrapper *wrapper, const char *url_from, int mo zend_string_efree(e->filename); efree(e); } - php_stream_wrapper_log_error(wrapper, options, "phar error: cannot create directory \"%s\" in phar \"%s\", directory already exists", ZSTR_VAL(resource->path)+1, ZSTR_VAL(resource->host)); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_ALREADY_EXISTS, + "phar error: cannot create directory \"%s\" in phar \"%s\", directory already exists", + ZSTR_VAL(resource->path)+1, ZSTR_VAL(resource->host)); php_url_free(resource); return 0; } if (error) { - php_stream_wrapper_log_error(wrapper, options, "phar error: cannot create directory \"%s\" in phar \"%s\", %s", ZSTR_VAL(resource->path)+1, ZSTR_VAL(resource->host), error); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_MKDIR_FAILED, + "phar error: cannot create directory \"%s\" in phar \"%s\", %s", + ZSTR_VAL(resource->path)+1, ZSTR_VAL(resource->host), error); efree(error); php_url_free(resource); return 0; @@ -412,13 +428,17 @@ int phar_wrapper_mkdir(php_stream_wrapper *wrapper, const char *url_from, int mo if (phar_get_entry_info_dir(phar, ZSTR_VAL(resource->path) + 1, ZSTR_LEN(resource->path) - 1, 0, &error, true)) { /* entry exists as a file */ - php_stream_wrapper_log_error(wrapper, options, "phar error: cannot create directory \"%s\" in phar \"%s\", file already exists", ZSTR_VAL(resource->path)+1, ZSTR_VAL(resource->host)); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_ALREADY_EXISTS, + "phar error: cannot create directory \"%s\" in phar \"%s\", file already exists", + ZSTR_VAL(resource->path)+1, ZSTR_VAL(resource->host)); php_url_free(resource); return 0; } if (error) { - php_stream_wrapper_log_error(wrapper, options, "phar error: cannot create directory \"%s\" in phar \"%s\", %s", ZSTR_VAL(resource->path)+1, ZSTR_VAL(resource->host), error); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_MKDIR_FAILED, + "phar error: cannot create directory \"%s\" in phar \"%s\", %s", + ZSTR_VAL(resource->path)+1, ZSTR_VAL(resource->host), error); efree(error); php_url_free(resource); return 0; @@ -447,7 +467,9 @@ int phar_wrapper_mkdir(php_stream_wrapper *wrapper, const char *url_from, int mo entry.old_flags = PHAR_ENT_PERM_DEF_DIR; if (NULL == zend_hash_add_mem(&phar->manifest, entry.filename, &entry, sizeof(phar_entry_info))) { - php_stream_wrapper_log_error(wrapper, options, "phar error: cannot create directory \"%s\" in phar \"%s\", adding to manifest failed", ZSTR_VAL(entry.filename), phar->fname); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_MKDIR_FAILED, + "phar error: cannot create directory \"%s\" in phar \"%s\", adding to manifest failed", + ZSTR_VAL(entry.filename), phar->fname); zend_string_efree(entry.filename); return 0; } @@ -455,7 +477,9 @@ int phar_wrapper_mkdir(php_stream_wrapper *wrapper, const char *url_from, int mo phar_flush(phar, &error); if (error) { - php_stream_wrapper_log_error(wrapper, options, "phar error: cannot create directory \"%s\" in phar \"%s\", %s", ZSTR_VAL(entry.filename), phar->fname, error); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_MKDIR_FAILED, + "phar error: cannot create directory \"%s\" in phar \"%s\", %s", + ZSTR_VAL(entry.filename), phar->fname, error); zend_hash_del(&phar->manifest, entry.filename); efree(error); return 0; @@ -479,7 +503,8 @@ int phar_wrapper_rmdir(php_stream_wrapper *wrapper, const char *url, int options /* pre-readonly check, we need to know if this is a data phar */ if (FAILURE == phar_split_fname(url, strlen(url), &arch, &arch_len, NULL, NULL, 2, 2)) { - php_stream_wrapper_log_error(wrapper, options, "phar error: cannot remove directory \"%s\", no phar archive specified, or phar archive does not exist", url); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_NOT_FOUND, + "phar error: cannot remove directory \"%s\", no phar archive specified, or phar archive does not exist", url); return 0; } @@ -490,7 +515,8 @@ int phar_wrapper_rmdir(php_stream_wrapper *wrapper, const char *url, int options efree(arch); if (PHAR_G(readonly) && (!phar || !phar->is_data)) { - php_stream_wrapper_log_error(wrapper, options, "phar error: cannot rmdir directory \"%s\", write operations disabled", url); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_READONLY, + "phar error: cannot rmdir directory \"%s\", write operations disabled", url); return 0; } @@ -501,18 +527,22 @@ int phar_wrapper_rmdir(php_stream_wrapper *wrapper, const char *url, int options /* we must have at the very least phar://alias.phar/internalfile.php */ if (!resource->scheme || !resource->host || !resource->path) { php_url_free(resource); - php_stream_wrapper_log_error(wrapper, options, "phar error: invalid url \"%s\"", url); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_INVALID_URL, + "phar error: invalid url \"%s\"", url); return 0; } if (!zend_string_equals_literal_ci(resource->scheme, "phar")) { php_url_free(resource); - php_stream_wrapper_log_error(wrapper, options, "phar error: not a phar stream url \"%s\"", url); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_PROTOCOL_UNSUPPORTED, + "phar error: not a phar stream url \"%s\"", url); return 0; } if (FAILURE == phar_get_archive(&phar, ZSTR_VAL(resource->host), ZSTR_LEN(resource->host), NULL, 0, &error)) { - php_stream_wrapper_log_error(wrapper, options, "phar error: cannot remove directory \"%s\" in phar \"%s\", error retrieving phar information: %s", ZSTR_VAL(resource->path)+1, ZSTR_VAL(resource->host), error); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_RMDIR_FAILED, + "phar error: cannot remove directory \"%s\" in phar \"%s\", error retrieving phar information: %s", + ZSTR_VAL(resource->path)+1, ZSTR_VAL(resource->host), error); efree(error); php_url_free(resource); return 0; @@ -522,10 +552,14 @@ int phar_wrapper_rmdir(php_stream_wrapper *wrapper, const char *url, int options if (!(entry = phar_get_entry_info_dir(phar, ZSTR_VAL(resource->path) + 1, path_len, 2, &error, true))) { if (error) { - php_stream_wrapper_log_error(wrapper, options, "phar error: cannot remove directory \"%s\" in phar \"%s\", %s", ZSTR_VAL(resource->path)+1, ZSTR_VAL(resource->host), error); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_RMDIR_FAILED, + "phar error: cannot remove directory \"%s\" in phar \"%s\", %s", + ZSTR_VAL(resource->path)+1, ZSTR_VAL(resource->host), error); efree(error); } else { - php_stream_wrapper_log_error(wrapper, options, "phar error: cannot remove directory \"%s\" in phar \"%s\", directory does not exist", ZSTR_VAL(resource->path)+1, ZSTR_VAL(resource->host)); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_NOT_FOUND, + "phar error: cannot remove directory \"%s\" in phar \"%s\", directory does not exist", + ZSTR_VAL(resource->path)+1, ZSTR_VAL(resource->host)); } php_url_free(resource); return 0; @@ -539,7 +573,8 @@ int phar_wrapper_rmdir(php_stream_wrapper *wrapper, const char *url, int options zend_string_starts_with_cstr(str_key, ZSTR_VAL(resource->path)+1, path_len) && IS_SLASH(ZSTR_VAL(str_key)[path_len]) ) { - php_stream_wrapper_log_error(wrapper, options, "phar error: Directory not empty"); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_RMDIR_FAILED, + "phar error: Directory not empty"); if (entry->is_temp_dir) { zend_string_efree(entry->filename); efree(entry); @@ -555,7 +590,8 @@ int phar_wrapper_rmdir(php_stream_wrapper *wrapper, const char *url, int options zend_string_starts_with_cstr(str_key, ZSTR_VAL(resource->path)+1, path_len) && IS_SLASH(ZSTR_VAL(str_key)[path_len]) ) { - php_stream_wrapper_log_error(wrapper, options, "phar error: Directory not empty"); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_RMDIR_FAILED, + "phar error: Directory not empty"); if (entry->is_temp_dir) { zend_string_efree(entry->filename); efree(entry); @@ -576,7 +612,9 @@ int phar_wrapper_rmdir(php_stream_wrapper *wrapper, const char *url, int options phar_flush(phar, &error); if (error) { - php_stream_wrapper_log_error(wrapper, options, "phar error: cannot remove directory \"%s\" in phar \"%s\", %s", ZSTR_VAL(entry->filename), phar->fname, error); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_RMDIR_FAILED, + "phar error: cannot remove directory \"%s\" in phar \"%s\", %s", + ZSTR_VAL(entry->filename), phar->fname, error); php_url_free(resource); efree(error); return 0; diff --git a/ext/phar/stream.c b/ext/phar/stream.c index 786b195517861..2250b070a13d2 100644 --- a/ext/phar/stream.c +++ b/ext/phar/stream.c @@ -68,17 +68,21 @@ php_url* phar_parse_url(php_stream_wrapper *wrapper, const char *filename, const } if (mode[0] == 'a') { if (!(options & PHP_STREAM_URL_STAT_QUIET)) { - php_stream_wrapper_log_error(wrapper, options, "phar error: open mode append not supported"); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_MODE_NOT_SUPPORTED, + "phar error: open mode append not supported"); } return NULL; } if (phar_split_fname(filename, strlen(filename), &arch, &arch_len, &entry, &entry_len, 2, (mode[0] == 'w' ? 2 : 0)) == FAILURE) { if (!(options & PHP_STREAM_URL_STAT_QUIET)) { if (arch && !entry) { - php_stream_wrapper_log_error(wrapper, options, "phar error: no directory in \"%s\", must have at least phar://%s/ for root directory (always use full path to a new phar)", filename, arch); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_INVALID_PATH, + "phar error: no directory in \"%s\", must have at least phar://%s/ for root directory (always use full path to a new phar)", + filename, arch); arch = NULL; } else { - php_stream_wrapper_log_error(wrapper, options, "phar error: invalid url or non-existent phar \"%s\"", filename); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_INVALID_URL, + "phar error: invalid url or non-existent phar \"%s\"", filename); } } return NULL; @@ -111,7 +115,8 @@ php_url* phar_parse_url(php_stream_wrapper *wrapper, const char *filename, const } if (PHAR_G(readonly) && (!pphar || !pphar->is_data)) { if (!(options & PHP_STREAM_URL_STAT_QUIET)) { - php_stream_wrapper_log_error(wrapper, options, "phar error: write operations disabled by the php.ini setting phar.readonly"); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_READONLY, + "phar error: write operations disabled by the php.ini setting phar.readonly"); } php_url_free(resource); return NULL; @@ -120,7 +125,7 @@ php_url* phar_parse_url(php_stream_wrapper *wrapper, const char *filename, const { if (error) { if (!(options & PHP_STREAM_URL_STAT_QUIET)) { - php_stream_wrapper_log_error(wrapper, options, "%s", error); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_GENERIC, "%s", error); } efree(error); } @@ -131,7 +136,7 @@ php_url* phar_parse_url(php_stream_wrapper *wrapper, const char *filename, const if (error) { spprintf(&error, 0, "Cannot open cached phar '%s' as writeable, copy on write failed", ZSTR_VAL(resource->host)); if (!(options & PHP_STREAM_URL_STAT_QUIET)) { - php_stream_wrapper_log_error(wrapper, options, "%s", error); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_GENERIC, "%s", error); } efree(error); } @@ -143,7 +148,7 @@ php_url* phar_parse_url(php_stream_wrapper *wrapper, const char *filename, const { if (error) { if (!(options & PHP_STREAM_URL_STAT_QUIET)) { - php_stream_wrapper_log_error(wrapper, options, "%s", error); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_NOT_FOUND, "%s", error); } efree(error); } @@ -176,13 +181,15 @@ static php_stream * phar_wrapper_open_url(php_stream_wrapper *wrapper, const cha /* we must have at the very least phar://alias.phar/internalfile.php */ if (!resource->scheme || !resource->host || !resource->path) { php_url_free(resource); - php_stream_wrapper_log_error(wrapper, options, "phar error: invalid url \"%s\"", path); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_INVALID_URL, + "phar error: invalid url \"%s\"", path); return NULL; } if (!zend_string_equals_literal_ci(resource->scheme, "phar")) { php_url_free(resource); - php_stream_wrapper_log_error(wrapper, options, "phar error: not a phar stream url \"%s\"", path); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_PROTOCOL_UNSUPPORTED, + "phar error: not a phar stream url \"%s\"", path); return NULL; } @@ -193,10 +200,11 @@ static php_stream * phar_wrapper_open_url(php_stream_wrapper *wrapper, const cha if (mode[0] == 'w' || (mode[0] == 'r' && mode[1] == '+')) { if (NULL == (idata = phar_get_or_create_entry_data(ZSTR_VAL(resource->host), ZSTR_LEN(resource->host), internal_file, strlen(internal_file), mode, 0, &error, true, time(NULL)))) { if (error) { - php_stream_wrapper_log_error(wrapper, options, "%s", error); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_GENERIC, "%s", error); efree(error); } else { - php_stream_wrapper_log_error(wrapper, options, "phar error: file \"%s\" could not be created in phar \"%s\"", internal_file, ZSTR_VAL(resource->host)); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_GENERIC, + "phar error: file \"%s\" could not be created in phar \"%s\"", internal_file, ZSTR_VAL(resource->host)); } efree(internal_file); php_url_free(resource); @@ -236,7 +244,8 @@ static php_stream * phar_wrapper_open_url(php_stream_wrapper *wrapper, const cha if (!*internal_file && (options & STREAM_OPEN_FOR_INCLUDE)) { /* retrieve the stub */ if (FAILURE == phar_get_archive(&phar, ZSTR_VAL(resource->host), ZSTR_LEN(resource->host), NULL, 0, NULL)) { - php_stream_wrapper_log_error(wrapper, options, "file %s is not a valid phar archive", ZSTR_VAL(resource->host)); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_INVALID_FORMAT, + "file %s is not a valid phar archive", ZSTR_VAL(resource->host)); efree(internal_file); php_url_free(resource); return NULL; @@ -256,7 +265,8 @@ static php_stream * phar_wrapper_open_url(php_stream_wrapper *wrapper, const cha if (stream == NULL) { stream = phar_open_archive_fp(phar); if (UNEXPECTED(!stream)) { - php_stream_wrapper_log_error(wrapper, options, "phar error: could not reopen phar \"%s\"", ZSTR_VAL(resource->host)); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_GENERIC, + "phar error: could not reopen phar \"%s\"", ZSTR_VAL(resource->host)); efree(internal_file); php_url_free(resource); return NULL; @@ -293,10 +303,11 @@ static php_stream * phar_wrapper_open_url(php_stream_wrapper *wrapper, const cha if ((FAILURE == phar_get_entry_data(&idata, ZSTR_VAL(resource->host), ZSTR_LEN(resource->host), internal_file, strlen(internal_file), "r", 0, &error, false)) || !idata) { idata_error: if (error) { - php_stream_wrapper_log_error(wrapper, options, "%s", error); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_NOT_FOUND, "%s", error); efree(error); } else { - php_stream_wrapper_log_error(wrapper, options, "phar error: \"%s\" is not a file in phar \"%s\"", internal_file, ZSTR_VAL(resource->host)); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_NOT_FOUND, + "phar error: \"%s\" is not a file in phar \"%s\"", internal_file, ZSTR_VAL(resource->host)); } efree(internal_file); php_url_free(resource); @@ -314,7 +325,7 @@ static php_stream * phar_wrapper_open_url(php_stream_wrapper *wrapper, const cha /* check length, crc32 */ if (!idata->internal_file->is_crc_checked && phar_postprocess_file(idata, idata->internal_file->crc32, &error, 2) != SUCCESS) { - php_stream_wrapper_log_error(wrapper, options, "%s", error); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_GENERIC, "%s", error); efree(error); phar_entry_delref(idata); efree(internal_file); @@ -445,7 +456,9 @@ static ssize_t phar_stream_write(php_stream *stream, const char *buf, size_t cou php_stream_seek(data->fp, data->position + data->zero, SEEK_SET); if (count != php_stream_write(data->fp, buf, count)) { - php_stream_wrapper_log_error(stream->wrapper, stream->flags, "phar error: Could not write %zu characters to \"%s\" in phar \"%s\"", count, ZSTR_VAL(data->internal_file->filename), data->phar->fname); + php_stream_wrapper_log_warn(stream->wrapper, stream->flags, STREAM_ERROR_CODE_WRITE_FAILED, + "phar error: Could not write %zu characters to \"%s\" in phar \"%s\"", + count, ZSTR_VAL(data->internal_file->filename), data->phar->fname); return -1; } data->position = php_stream_tell(data->fp) - data->zero; @@ -472,7 +485,7 @@ static int phar_stream_flush(php_stream *stream) /* {{{ */ data->internal_file->timestamp = time(0); ret = phar_flush(data->phar, &error); if (error) { - php_stream_wrapper_log_error(stream->wrapper, REPORT_ERRORS, "%s", error); + php_stream_wrapper_log_warn(stream->wrapper, REPORT_ERRORS, STREAM_ERROR_CODE_FLUSH_FAILED, "%s", error); efree(error); } return ret; @@ -665,20 +678,23 @@ static int phar_wrapper_unlink(php_stream_wrapper *wrapper, const char *url, int phar_archive_data *pphar; if ((resource = phar_parse_url(wrapper, url, "rb", options)) == NULL) { - php_stream_wrapper_log_error(wrapper, options, "phar error: unlink failed"); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_UNLINK_FAILED, + "phar error: unlink failed"); return 0; } /* we must have at the very least phar://alias.phar/internalfile.php */ if (!resource->scheme || !resource->host || !resource->path) { php_url_free(resource); - php_stream_wrapper_log_error(wrapper, options, "phar error: invalid url \"%s\"", url); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_INVALID_URL, + "phar error: invalid url \"%s\"", url); return 0; } if (!zend_string_equals_literal_ci(resource->scheme, "phar")) { php_url_free(resource); - php_stream_wrapper_log_error(wrapper, options, "phar error: not a phar stream url \"%s\"", url); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_PROTOCOL_UNSUPPORTED, + "phar error: not a phar stream url \"%s\"", url); return 0; } @@ -687,7 +703,8 @@ static int phar_wrapper_unlink(php_stream_wrapper *wrapper, const char *url, int pphar = zend_hash_find_ptr(&(PHAR_G(phar_fname_map)), resource->host); if (PHAR_G(readonly) && (!pphar || !pphar->is_data)) { php_url_free(resource); - php_stream_wrapper_log_error(wrapper, options, "phar error: write operations disabled by the php.ini setting phar.readonly"); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_READONLY, + "phar error: write operations disabled by the php.ini setting phar.readonly"); return 0; } @@ -697,10 +714,12 @@ static int phar_wrapper_unlink(php_stream_wrapper *wrapper, const char *url, int if (FAILURE == phar_get_entry_data(&idata, ZSTR_VAL(resource->host), ZSTR_LEN(resource->host), internal_file, internal_file_len, "r", 0, &error, true)) { /* constraints of fp refcount were not met */ if (error) { - php_stream_wrapper_log_error(wrapper, options, "unlink of \"%s\" failed: %s", url, error); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_UNLINK_FAILED, + "unlink of \"%s\" failed: %s", url, error); efree(error); } else { - php_stream_wrapper_log_error(wrapper, options, "unlink of \"%s\" failed, file does not exist", url); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_NOT_FOUND, + "unlink of \"%s\" failed, file does not exist", url); } efree(internal_file); php_url_free(resource); @@ -711,7 +730,9 @@ static int phar_wrapper_unlink(php_stream_wrapper *wrapper, const char *url, int } if (idata->internal_file->fp_refcount > 1) { /* more than just our fp resource is open for this file */ - php_stream_wrapper_log_error(wrapper, options, "phar error: \"%s\" in phar \"%s\", has open file pointers, cannot unlink", internal_file, ZSTR_VAL(resource->host)); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_UNLINK_FAILED, + "phar error: \"%s\" in phar \"%s\", has open file pointers, cannot unlink", + internal_file, ZSTR_VAL(resource->host)); efree(internal_file); php_url_free(resource); phar_entry_delref(idata); @@ -721,7 +742,7 @@ static int phar_wrapper_unlink(php_stream_wrapper *wrapper, const char *url, int efree(internal_file); phar_entry_remove(idata, &error); if (error) { - php_stream_wrapper_log_error(wrapper, options, "%s", error); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_UNLINK_FAILED, "%s", error); efree(error); } return 1; @@ -740,7 +761,9 @@ static int phar_wrapper_rename(php_stream_wrapper *wrapper, const char *url_from error = NULL; if ((resource_from = phar_parse_url(wrapper, url_from, "wb", options|PHP_STREAM_URL_STAT_QUIET)) == NULL) { - php_error_docref(NULL, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\": invalid or non-writable url \"%s\"", url_from, url_to, url_from); + php_stream_wrapper_warn(wrapper, context, options, STREAM_ERROR_CODE_INVALID_URL, + "phar error: cannot rename \"%s\" to \"%s\": invalid or non-writable url \"%s\"", + url_from, url_to, url_from); return 0; } if (SUCCESS != phar_get_archive(&pfrom, ZSTR_VAL(resource_from->host), ZSTR_LEN(resource_from->host), NULL, 0, &error)) { @@ -751,13 +774,16 @@ static int phar_wrapper_rename(php_stream_wrapper *wrapper, const char *url_from } if (PHAR_G(readonly) && (!pfrom || !pfrom->is_data)) { php_url_free(resource_from); - php_error_docref(NULL, E_WARNING, "phar error: Write operations disabled by the php.ini setting phar.readonly"); + php_stream_wrapper_warn(wrapper, context, options, STREAM_ERROR_CODE_READONLY, + "phar error: Write operations disabled by the php.ini setting phar.readonly"); return 0; } if ((resource_to = phar_parse_url(wrapper, url_to, "wb", options|PHP_STREAM_URL_STAT_QUIET)) == NULL) { php_url_free(resource_from); - php_error_docref(NULL, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\": invalid or non-writable url \"%s\"", url_from, url_to, url_to); + php_stream_wrapper_warn(wrapper, context, options, STREAM_ERROR_CODE_INVALID_URL, + "phar error: cannot rename \"%s\" to \"%s\": invalid or non-writable url \"%s\"", + url_from, url_to, url_to); return 0; } if (SUCCESS != phar_get_archive(&pto, ZSTR_VAL(resource_to->host), ZSTR_LEN(resource_to->host), NULL, 0, &error)) { @@ -769,14 +795,17 @@ static int phar_wrapper_rename(php_stream_wrapper *wrapper, const char *url_from if (PHAR_G(readonly) && (!pto || !pto->is_data)) { php_url_free(resource_from); php_url_free(resource_to); - php_error_docref(NULL, E_WARNING, "phar error: Write operations disabled by the php.ini setting phar.readonly"); + php_stream_wrapper_warn(wrapper, context, options, STREAM_ERROR_CODE_READONLY, + "phar error: Write operations disabled by the php.ini setting phar.readonly"); return 0; } if (!zend_string_equals(resource_from->host, resource_to->host)) { php_url_free(resource_from); php_url_free(resource_to); - php_error_docref(NULL, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\", not within the same phar archive", url_from, url_to); + php_stream_wrapper_warn(wrapper, context, options, STREAM_ERROR_CODE_RENAME_FAILED, + "phar error: cannot rename \"%s\" to \"%s\", not within the same phar archive", + url_from, url_to); return 0; } @@ -784,35 +813,44 @@ static int phar_wrapper_rename(php_stream_wrapper *wrapper, const char *url_from if (!resource_from->scheme || !resource_from->host || !resource_from->path) { php_url_free(resource_from); php_url_free(resource_to); - php_error_docref(NULL, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\": invalid url \"%s\"", url_from, url_to, url_from); + php_stream_wrapper_warn(wrapper, context, options, STREAM_ERROR_CODE_INVALID_URL, + "phar error: cannot rename \"%s\" to \"%s\": invalid url \"%s\"", + url_from, url_to, url_from); return 0; } if (!resource_to->scheme || !resource_to->host || !resource_to->path) { php_url_free(resource_from); php_url_free(resource_to); - php_error_docref(NULL, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\": invalid url \"%s\"", url_from, url_to, url_to); + php_stream_wrapper_warn(wrapper, context, options, STREAM_ERROR_CODE_INVALID_URL, + "phar error: cannot rename \"%s\" to \"%s\": invalid url \"%s\"", + url_from, url_to, url_to); return 0; } if (!zend_string_equals_literal_ci(resource_from->scheme, "phar")) { php_url_free(resource_from); php_url_free(resource_to); - php_error_docref(NULL, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\": not a phar stream url \"%s\"", url_from, url_to, url_from); + php_stream_wrapper_warn(wrapper, context, options, STREAM_ERROR_CODE_PROTOCOL_UNSUPPORTED, + "phar error: cannot rename \"%s\" to \"%s\": not a phar stream url \"%s\"", + url_from, url_to, url_from); return 0; } if (!zend_string_equals_literal_ci(resource_to->scheme, "phar")) { php_url_free(resource_from); php_url_free(resource_to); - php_error_docref(NULL, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\": not a phar stream url \"%s\"", url_from, url_to, url_to); + php_stream_wrapper_warn(wrapper, context, options, STREAM_ERROR_CODE_PROTOCOL_UNSUPPORTED, + "phar error: cannot rename \"%s\" to \"%s\": not a phar stream url \"%s\"", + url_from, url_to, url_to); return 0; } if (SUCCESS != phar_get_archive(&phar, ZSTR_VAL(resource_from->host), ZSTR_LEN(resource_from->host), NULL, 0, &error)) { php_url_free(resource_from); php_url_free(resource_to); - php_error_docref(NULL, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\": %s", url_from, url_to, error); + php_stream_wrapper_warn(wrapper, context, options, STREAM_ERROR_CODE_RENAME_FAILED, + "phar error: cannot rename \"%s\" to \"%s\": %s", url_from, url_to, error); efree(error); return 0; } @@ -820,7 +858,9 @@ static int phar_wrapper_rename(php_stream_wrapper *wrapper, const char *url_from if (phar->is_persistent && FAILURE == phar_copy_on_write(&phar)) { php_url_free(resource_from); php_url_free(resource_to); - php_error_docref(NULL, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\": could not make cached phar writeable", url_from, url_to); + php_stream_wrapper_warn(wrapper, context, options, STREAM_ERROR_CODE_RENAME_FAILED, + "phar error: cannot rename \"%s\" to \"%s\": could not make cached phar writeable", + url_from, url_to); return 0; } @@ -831,7 +871,9 @@ static int phar_wrapper_rename(php_stream_wrapper *wrapper, const char *url_from if (entry->is_deleted) { php_url_free(resource_from); php_url_free(resource_to); - php_error_docref(NULL, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\" from extracted phar archive, source has been deleted", url_from, url_to); + php_stream_wrapper_warn(wrapper, context, options, STREAM_ERROR_CODE_NOT_FOUND, + "phar error: cannot rename \"%s\" to \"%s\" from extracted phar archive, source has been deleted", + url_from, url_to); return 0; } /* transfer all data over to the new entry */ @@ -851,7 +893,8 @@ static int phar_wrapper_rename(php_stream_wrapper *wrapper, const char *url_from if (FAILURE == phar_copy_entry_fp(source, entry, &error)) { php_url_free(resource_from); php_url_free(resource_to); - php_error_docref(NULL, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\": %s", url_from, url_to, error); + php_stream_wrapper_warn(wrapper, context, options, STREAM_ERROR_CODE_RENAME_FAILED, + "phar error: cannot rename \"%s\" to \"%s\": %s", url_from, url_to, error); efree(error); zend_hash_del(&phar->manifest, entry->filename); return 0; @@ -865,7 +908,9 @@ static int phar_wrapper_rename(php_stream_wrapper *wrapper, const char *url_from /* file does not exist */ php_url_free(resource_from); php_url_free(resource_to); - php_error_docref(NULL, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\" from extracted phar archive, source does not exist", url_from, url_to); + php_stream_wrapper_warn(wrapper, context, options, STREAM_ERROR_CODE_NOT_FOUND, + "phar error: cannot rename \"%s\" to \"%s\" from extracted phar archive, source does not exist", + url_from, url_to); return 0; } @@ -944,7 +989,8 @@ static int phar_wrapper_rename(php_stream_wrapper *wrapper, const char *url_from if (error) { php_url_free(resource_from); php_url_free(resource_to); - php_error_docref(NULL, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\": %s", url_from, url_to, error); + php_stream_wrapper_warn(wrapper, context, options, STREAM_ERROR_CODE_RENAME_FAILED, + "phar error: cannot rename \"%s\" to \"%s\": %s", url_from, url_to, error); efree(error); return 0; } From 4f56e7ed104c08d31563c9750b11cf6c3ddb6f25 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Sun, 16 Nov 2025 16:55:22 +0100 Subject: [PATCH 04/68] stream: convert ftp wrapper errors --- ext/standard/ftp_fopen_wrapper.c | 78 +++++++++++++++++++++----------- 1 file changed, 52 insertions(+), 26 deletions(-) diff --git a/ext/standard/ftp_fopen_wrapper.c b/ext/standard/ftp_fopen_wrapper.c index 92200e64f2384..82e2c040636d5 100644 --- a/ext/standard/ftp_fopen_wrapper.c +++ b/ext/standard/ftp_fopen_wrapper.c @@ -108,7 +108,9 @@ static int php_stream_ftp_stream_close(php_stream_wrapper *wrapper, php_stream * /* For write modes close data stream first to signal EOF to server */ result = GET_FTP_RESULT(controlstream); if (result != 226 && result != 250) { - php_error_docref(NULL, E_WARNING, "FTP server error %d:%s", result, tmp_line); + php_stream_wrapper_warn(wrapper, PHP_STREAM_CONTEXT(stream), REPORT_ERRORS, + STREAM_ERROR_CODE_PROTOCOL_ERROR, + "FTP server error %d:%s", result, tmp_line); ret = EOF; } } @@ -186,7 +188,8 @@ static php_stream *php_ftp_fopen_connect(php_stream_wrapper *wrapper, const char /* get the response */ result = GET_FTP_RESULT(stream); if (result != 334) { - php_stream_wrapper_log_error(wrapper, options, "Server doesn't support FTPS."); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_SSL_NOT_SUPPORTED, + "Server doesn't support FTPS."); goto connect_errexit; } else { /* we must reuse the old SSL session id */ @@ -205,7 +208,8 @@ static php_stream *php_ftp_fopen_connect(php_stream_wrapper *wrapper, const char if (php_stream_xport_crypto_setup(stream, STREAM_CRYPTO_METHOD_SSLv23_CLIENT, NULL) < 0 || php_stream_xport_crypto_enable(stream, 1) < 0) { - php_stream_wrapper_log_error(wrapper, options, "Unable to activate SSL mode"); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_SSL_NOT_SUPPORTED, + "Unable to activate SSL mode"); php_stream_close(stream); stream = NULL; goto connect_errexit; @@ -236,7 +240,7 @@ static php_stream *php_ftp_fopen_connect(php_stream_wrapper *wrapper, const char unsigned char *s = (unsigned char *) val, *e = (unsigned char *) s + val_len; \ while (s < e) { \ if (iscntrl(*s)) { \ - php_stream_wrapper_log_error(wrapper, options, err_msg, val); \ + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_AUTH_FAILED, err_msg, val); \ goto connect_errexit; \ } \ s++; \ @@ -433,7 +437,8 @@ php_stream * php_stream_url_wrap_ftp(php_stream_wrapper *wrapper, const char *pa } if (strpbrk(mode, "wa+")) { if (read_write) { - php_stream_wrapper_log_error(wrapper, options, "FTP does not support simultaneous read/write connections"); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_MODE_NOT_SUPPORTED, + "FTP does not support simultaneous read/write connections"); return NULL; } if (strchr(mode, 'a')) { @@ -444,7 +449,8 @@ php_stream * php_stream_url_wrap_ftp(php_stream_wrapper *wrapper, const char *pa } if (!read_write) { /* No mode specified? */ - php_stream_wrapper_log_error(wrapper, options, "Unknown file open mode"); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_INVALID_MODE, + "Unknown file open mode"); return NULL; } @@ -455,7 +461,8 @@ php_stream * php_stream_url_wrap_ftp(php_stream_wrapper *wrapper, const char *pa return php_stream_url_wrap_http(wrapper, path, mode, options, opened_path, context STREAMS_CC); } else { /* ftp proxy is read-only */ - php_stream_wrapper_log_error(wrapper, options, "FTP proxy may only be used in read mode"); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_MODE_NOT_SUPPORTED, + "FTP proxy may only be used in read mode"); return NULL; } } @@ -507,7 +514,8 @@ php_stream * php_stream_url_wrap_ftp(php_stream_wrapper *wrapper, const char *pa goto errexit; } } else { - php_stream_wrapper_log_error(wrapper, options, "Remote file already exists and overwrite context option not specified"); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_ALREADY_EXISTS, + "Remote file already exists and overwrite context option not specified"); errno = EEXIST; goto errexit; } @@ -531,7 +539,8 @@ php_stream * php_stream_url_wrap_ftp(php_stream_wrapper *wrapper, const char *pa php_stream_printf(stream, "REST " ZEND_LONG_FMT "\r\n", Z_LVAL_P(tmpzval)); result = GET_FTP_RESULT(stream); if (result < 300 || result > 399) { - php_stream_wrapper_log_error(wrapper, options, "Unable to resume from offset " ZEND_LONG_FMT, Z_LVAL_P(tmpzval)); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_GENERIC, + "Unable to resume from offset " ZEND_LONG_FMT, Z_LVAL_P(tmpzval)); goto errexit; } } @@ -576,7 +585,8 @@ php_stream * php_stream_url_wrap_ftp(php_stream_wrapper *wrapper, const char *pa STREAM_CRYPTO_METHOD_SSLv23_CLIENT, NULL) < 0 || php_stream_xport_crypto_enable(datastream, 1) < 0)) { - php_stream_wrapper_log_error(wrapper, options, "Unable to activate SSL mode"); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_SSL_NOT_SUPPORTED, + "Unable to activate SSL mode"); php_stream_close(datastream); datastream = NULL; tmp_line[0]='\0'; @@ -598,10 +608,12 @@ php_stream * php_stream_url_wrap_ftp(php_stream_wrapper *wrapper, const char *pa php_stream_close(stream); } if (tmp_line[0] != '\0') - php_stream_wrapper_log_error(wrapper, options, "FTP server reports %s", tmp_line); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_PROTOCOL_ERROR, + "FTP server reports %s", tmp_line); if (error_message) { - php_stream_wrapper_log_error(wrapper, options, "Failed to set up data channel: %s", ZSTR_VAL(error_message)); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_NETWORK_SEND_FAILED, + "Failed to set up data channel: %s", ZSTR_VAL(error_message)); zend_string_release(error_message); } return NULL; @@ -746,7 +758,8 @@ static php_stream * php_stream_ftp_opendir(php_stream_wrapper *wrapper, const ch STREAM_CRYPTO_METHOD_SSLv23_CLIENT, NULL) < 0 || php_stream_xport_crypto_enable(datastream, 1) < 0)) { - php_stream_wrapper_log_error(wrapper, options, "Unable to activate SSL mode"); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_SSL_NOT_SUPPORTED, + "Unable to activate SSL mode"); php_stream_close(datastream); datastream = NULL; goto opendir_errexit; @@ -770,7 +783,8 @@ static php_stream * php_stream_ftp_opendir(php_stream_wrapper *wrapper, const ch php_stream_close(stream); } if (tmp_line[0] != '\0') { - php_stream_wrapper_log_error(wrapper, options, "FTP server reports %s", tmp_line); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_PROTOCOL_ERROR, + "FTP server reports %s", tmp_line); } return NULL; } @@ -909,14 +923,16 @@ static int php_stream_ftp_unlink(php_stream_wrapper *wrapper, const char *url, i stream = php_ftp_fopen_connect(wrapper, url, "r", 0, NULL, context, NULL, &resource, NULL, NULL); if (!stream) { if (options & REPORT_ERRORS) { - php_error_docref(NULL, E_WARNING, "Unable to connect to %s", url); + php_stream_wrapper_warn(wrapper, context, options, STREAM_ERROR_CODE_AUTH_FAILED, + "Unable to connect to %s", url); } goto unlink_errexit; } if (resource->path == NULL) { if (options & REPORT_ERRORS) { - php_error_docref(NULL, E_WARNING, "Invalid path provided in %s", url); + php_stream_wrapper_warn(wrapper, context, options, STREAM_ERROR_CODE_INVALID_PATH, + "Invalid path provided in %s", url); } goto unlink_errexit; } @@ -927,7 +943,8 @@ static int php_stream_ftp_unlink(php_stream_wrapper *wrapper, const char *url, i result = GET_FTP_RESULT(stream); if (result < 200 || result > 299) { if (options & REPORT_ERRORS) { - php_error_docref(NULL, E_WARNING, "Error Deleting file: %s", tmp_line); + php_stream_wrapper_warn(wrapper, context, options, STREAM_ERROR_CODE_UNLINK_FAILED, + "Error Deleting file: %s", tmp_line); } goto unlink_errexit; } @@ -991,7 +1008,8 @@ static int php_stream_ftp_rename(php_stream_wrapper *wrapper, const char *url_fr stream = php_ftp_fopen_connect(wrapper, url_from, "r", 0, NULL, context, NULL, NULL, NULL, NULL); if (!stream) { if (options & REPORT_ERRORS) { - php_error_docref(NULL, E_WARNING, "Unable to connect to %s", ZSTR_VAL(resource_from->host)); + php_stream_wrapper_warn(wrapper, context, options, STREAM_ERROR_CODE_AUTH_FAILED, + "Unable to connect to %s", ZSTR_VAL(resource_from->host)); } goto rename_errexit; } @@ -1002,7 +1020,8 @@ static int php_stream_ftp_rename(php_stream_wrapper *wrapper, const char *url_fr result = GET_FTP_RESULT(stream); if (result < 300 || result > 399) { if (options & REPORT_ERRORS) { - php_error_docref(NULL, E_WARNING, "Error Renaming file: %s", tmp_line); + php_stream_wrapper_warn(wrapper, context, options, STREAM_ERROR_CODE_RENAME_FAILED, + "Error Renaming file: %s", tmp_line); } goto rename_errexit; } @@ -1013,7 +1032,8 @@ static int php_stream_ftp_rename(php_stream_wrapper *wrapper, const char *url_fr result = GET_FTP_RESULT(stream); if (result < 200 || result > 299) { if (options & REPORT_ERRORS) { - php_error_docref(NULL, E_WARNING, "Error Renaming file: %s", tmp_line); + php_stream_wrapper_warn(wrapper, context, options, STREAM_ERROR_CODE_RENAME_FAILED, + "Error Renaming file: %s", tmp_line); } goto rename_errexit; } @@ -1046,14 +1066,16 @@ static int php_stream_ftp_mkdir(php_stream_wrapper *wrapper, const char *url, in stream = php_ftp_fopen_connect(wrapper, url, "r", 0, NULL, context, NULL, &resource, NULL, NULL); if (!stream) { if (options & REPORT_ERRORS) { - php_error_docref(NULL, E_WARNING, "Unable to connect to %s", url); + php_stream_wrapper_warn(wrapper, context, options, STREAM_ERROR_CODE_AUTH_FAILED, + "Unable to connect to %s", url); } goto mkdir_errexit; } if (resource->path == NULL) { if (options & REPORT_ERRORS) { - php_error_docref(NULL, E_WARNING, "Invalid path provided in %s", url); + php_stream_wrapper_warn(wrapper, context, options, STREAM_ERROR_CODE_INVALID_PATH, + "Invalid path provided in %s", url); } goto mkdir_errexit; } @@ -1094,7 +1116,8 @@ static int php_stream_ftp_mkdir(php_stream_wrapper *wrapper, const char *url, in result = GET_FTP_RESULT(stream); if (result < 200 || result > 299) { if (options & REPORT_ERRORS) { - php_error_docref(NULL, E_WARNING, "%s", tmp_line); + php_stream_wrapper_warn(wrapper, context, options, STREAM_ERROR_CODE_MKDIR_FAILED, + "%s", tmp_line); } break; } @@ -1138,14 +1161,16 @@ static int php_stream_ftp_rmdir(php_stream_wrapper *wrapper, const char *url, in stream = php_ftp_fopen_connect(wrapper, url, "r", 0, NULL, context, NULL, &resource, NULL, NULL); if (!stream) { if (options & REPORT_ERRORS) { - php_error_docref(NULL, E_WARNING, "Unable to connect to %s", url); + php_stream_wrapper_warn(wrapper, context, options, STREAM_ERROR_CODE_AUTH_FAILED, + "Unable to connect to %s", url); } goto rmdir_errexit; } if (resource->path == NULL) { if (options & REPORT_ERRORS) { - php_error_docref(NULL, E_WARNING, "Invalid path provided in %s", url); + php_stream_wrapper_warn(wrapper, context, options, STREAM_ERROR_CODE_INVALID_PATH, + "Invalid path provided in %s", url); } goto rmdir_errexit; } @@ -1155,7 +1180,8 @@ static int php_stream_ftp_rmdir(php_stream_wrapper *wrapper, const char *url, in if (result < 200 || result > 299) { if (options & REPORT_ERRORS) { - php_error_docref(NULL, E_WARNING, "%s", tmp_line); + php_stream_wrapper_warn(wrapper, context, options, STREAM_ERROR_CODE_RMDIR_FAILED, + "%s", tmp_line); } goto rmdir_errexit; } From 5979d7e96c465f7aa18bda77fc1474c70cd987a4 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Sun, 16 Nov 2025 17:44:50 +0100 Subject: [PATCH 05/68] stream: add few more errors to replace generic errors in phar and ftp --- ext/phar/stream.c | 12 +++---- ext/standard/ftp_fopen_wrapper.c | 2 +- main/streams/php_stream_errors.h | 48 +++++++++++++++------------- main/streams/stream_errors.stub.php | 20 ++++++++++++ main/streams/stream_errors_arginfo.h | 6 +++- 5 files changed, 58 insertions(+), 30 deletions(-) diff --git a/ext/phar/stream.c b/ext/phar/stream.c index 2250b070a13d2..f8575a499407a 100644 --- a/ext/phar/stream.c +++ b/ext/phar/stream.c @@ -125,7 +125,7 @@ php_url* phar_parse_url(php_stream_wrapper *wrapper, const char *filename, const { if (error) { if (!(options & PHP_STREAM_URL_STAT_QUIET)) { - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_GENERIC, "%s", error); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_OPEN_FAILED, "%s", error); } efree(error); } @@ -136,7 +136,7 @@ php_url* phar_parse_url(php_stream_wrapper *wrapper, const char *filename, const if (error) { spprintf(&error, 0, "Cannot open cached phar '%s' as writeable, copy on write failed", ZSTR_VAL(resource->host)); if (!(options & PHP_STREAM_URL_STAT_QUIET)) { - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_GENERIC, "%s", error); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_OPEN_FAILED, "%s", error); } efree(error); } @@ -200,10 +200,10 @@ static php_stream * phar_wrapper_open_url(php_stream_wrapper *wrapper, const cha if (mode[0] == 'w' || (mode[0] == 'r' && mode[1] == '+')) { if (NULL == (idata = phar_get_or_create_entry_data(ZSTR_VAL(resource->host), ZSTR_LEN(resource->host), internal_file, strlen(internal_file), mode, 0, &error, true, time(NULL)))) { if (error) { - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_GENERIC, "%s", error); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_CREATE_FAILED, "%s", error); efree(error); } else { - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_GENERIC, + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_CREATE_FAILED, "phar error: file \"%s\" could not be created in phar \"%s\"", internal_file, ZSTR_VAL(resource->host)); } efree(internal_file); @@ -265,7 +265,7 @@ static php_stream * phar_wrapper_open_url(php_stream_wrapper *wrapper, const cha if (stream == NULL) { stream = phar_open_archive_fp(phar); if (UNEXPECTED(!stream)) { - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_GENERIC, + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_OPEN_FAILED, "phar error: could not reopen phar \"%s\"", ZSTR_VAL(resource->host)); efree(internal_file); php_url_free(resource); @@ -325,7 +325,7 @@ static php_stream * phar_wrapper_open_url(php_stream_wrapper *wrapper, const cha /* check length, crc32 */ if (!idata->internal_file->is_crc_checked && phar_postprocess_file(idata, idata->internal_file->crc32, &error, 2) != SUCCESS) { - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_GENERIC, "%s", error); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_ARCHIVING_FAILED, "%s", error); efree(error); phar_entry_delref(idata); efree(internal_file); diff --git a/ext/standard/ftp_fopen_wrapper.c b/ext/standard/ftp_fopen_wrapper.c index 82e2c040636d5..3c5a490660c8d 100644 --- a/ext/standard/ftp_fopen_wrapper.c +++ b/ext/standard/ftp_fopen_wrapper.c @@ -539,7 +539,7 @@ php_stream * php_stream_url_wrap_ftp(php_stream_wrapper *wrapper, const char *pa php_stream_printf(stream, "REST " ZEND_LONG_FMT "\r\n", Z_LVAL_P(tmpzval)); result = GET_FTP_RESULT(stream); if (result < 300 || result > 399) { - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_GENERIC, + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_RESUMPTION_FAILED, "Unable to resume from offset " ZEND_LONG_FMT, Z_LVAL_P(tmpzval)); goto errexit; } diff --git a/main/streams/php_stream_errors.h b/main/streams/php_stream_errors.h index 5331000dfe149..f36ece142bc06 100644 --- a/main/streams/php_stream_errors.h +++ b/main/streams/php_stream_errors.h @@ -54,18 +54,20 @@ BEGIN_EXTERN_C() #define STREAM_ERROR_CODE_ALREADY_EXISTS 32 #define STREAM_ERROR_CODE_INVALID_PATH 33 #define STREAM_ERROR_CODE_PATH_TOO_LONG 34 -#define STREAM_ERROR_CODE_UNLINK_FAILED 35 -#define STREAM_ERROR_CODE_RENAME_FAILED 36 -#define STREAM_ERROR_CODE_MKDIR_FAILED 37 -#define STREAM_ERROR_CODE_RMDIR_FAILED 38 -#define STREAM_ERROR_CODE_STAT_FAILED 39 -#define STREAM_ERROR_CODE_CHMOD_FAILED 40 -#define STREAM_ERROR_CODE_CHOWN_FAILED 41 -#define STREAM_ERROR_CODE_TOUCH_FAILED 42 -#define STREAM_ERROR_CODE_INVALID_MODE 43 -#define STREAM_ERROR_CODE_MODE_NOT_SUPPORTED 44 -#define STREAM_ERROR_CODE_READONLY 45 -#define STREAM_ERROR_CODE_RECURSION_DETECTED 46 +#define STREAM_ERROR_CODE_OPEN_FAILED 35 +#define STREAM_ERROR_CODE_CREATE_FAILED 36 +#define STREAM_ERROR_CODE_UNLINK_FAILED 37 +#define STREAM_ERROR_CODE_RENAME_FAILED 38 +#define STREAM_ERROR_CODE_MKDIR_FAILED 39 +#define STREAM_ERROR_CODE_RMDIR_FAILED 40 +#define STREAM_ERROR_CODE_STAT_FAILED 41 +#define STREAM_ERROR_CODE_CHMOD_FAILED 42 +#define STREAM_ERROR_CODE_CHOWN_FAILED 43 +#define STREAM_ERROR_CODE_TOUCH_FAILED 44 +#define STREAM_ERROR_CODE_INVALID_MODE 45 +#define STREAM_ERROR_CODE_MODE_NOT_SUPPORTED 46 +#define STREAM_ERROR_CODE_READONLY 47 +#define STREAM_ERROR_CODE_RECURSION_DETECTED 48 /* Wrapper/protocol operations */ #define STREAM_ERROR_CODE_WRAPPER_NOT_FOUND 60 #define STREAM_ERROR_CODE_WRAPPER_DISABLED 61 @@ -85,16 +87,18 @@ BEGIN_EXTERN_C() #define STREAM_ERROR_CODE_NETWORK_SEND_FAILED 100 #define STREAM_ERROR_CODE_NETWORK_RECV_FAILED 101 #define STREAM_ERROR_CODE_SSL_NOT_SUPPORTED 102 -#define STREAM_ERROR_CODE_SOCKET_PATH_TOO_LONG 103 -#define STREAM_ERROR_CODE_OOB_NOT_SUPPORTED 104 -#define STREAM_ERROR_CODE_PROTOCOL_ERROR 105 -#define STREAM_ERROR_CODE_INVALID_URL 106 -#define STREAM_ERROR_CODE_INVALID_RESPONSE 107 -#define STREAM_ERROR_CODE_REDIRECT_LIMIT 108 -#define STREAM_ERROR_CODE_AUTH_FAILED 109 -/* Encoding/decoding operations */ -#define STREAM_ERROR_CODE_ENCODING_FAILED 120 -#define STREAM_ERROR_CODE_INVALID_FORMAT 121 +#define STREAM_ERROR_CODE_RESUMPTION_FAILED 103 +#define STREAM_ERROR_CODE_SOCKET_PATH_TOO_LONG 104 +#define STREAM_ERROR_CODE_OOB_NOT_SUPPORTED 105 +#define STREAM_ERROR_CODE_PROTOCOL_ERROR 106 +#define STREAM_ERROR_CODE_INVALID_URL 107 +#define STREAM_ERROR_CODE_INVALID_RESPONSE 108 +#define STREAM_ERROR_CODE_REDIRECT_LIMIT 109 +#define STREAM_ERROR_CODE_AUTH_FAILED 110 +/* Encoding/decoding/archiving operations */ +#define STREAM_ERROR_CODE_ARCHIVING_FAILED 120 +#define STREAM_ERROR_CODE_ENCODING_FAILED 121 +#define STREAM_ERROR_CODE_INVALID_FORMAT 122 /* Resource/allocation operations */ #define STREAM_ERROR_CODE_ALLOCATION_FAILED 130 #define STREAM_ERROR_CODE_TEMPORARY_FILE_FAILED 131 diff --git a/main/streams/stream_errors.stub.php b/main/streams/stream_errors.stub.php index fb660ad6e56c5..a9d090858aff6 100644 --- a/main/streams/stream_errors.stub.php +++ b/main/streams/stream_errors.stub.php @@ -86,6 +86,16 @@ public function getWrapperName(): string {} * @cvalue STREAM_ERROR_CODE_PATH_TOO_LONG */ const STREAM_ERROR_CODE_PATH_TOO_LONG = UNKNOWN; +/** + * @var int + * @cvalue STREAM_ERROR_CODE_CREATE_FAILED + */ +const STREAM_ERROR_CODE_CREATE_FAILED = UNKNOWN; +/** + * @var int + * @cvalue STREAM_ERROR_CODE_OPEN_FAILED + */ +const STREAM_ERROR_CODE_OPEN_FAILED = UNKNOWN; /** * @var int * @cvalue STREAM_ERROR_CODE_UNLINK_FAILED @@ -221,6 +231,11 @@ public function getWrapperName(): string {} * @cvalue STREAM_ERROR_CODE_SSL_NOT_SUPPORTED */ const STREAM_ERROR_CODE_SSL_NOT_SUPPORTED = UNKNOWN; +/** + * @var int + * @cvalue STREAM_ERROR_CODE_RESUMPTION_FAILED + */ +const STREAM_ERROR_CODE_RESUMPTION_FAILED = UNKNOWN; /** * @var int * @cvalue STREAM_ERROR_CODE_SOCKET_PATH_TOO_LONG @@ -256,6 +271,11 @@ public function getWrapperName(): string {} * @cvalue STREAM_ERROR_CODE_AUTH_FAILED */ const STREAM_ERROR_CODE_AUTH_FAILED = UNKNOWN; +/** + * @var int + * @cvalue STREAM_ERROR_CODE_ARCHIVING_FAILED + */ +const STREAM_ERROR_CODE_ARCHIVING_FAILED = UNKNOWN; /** * @var int * @cvalue STREAM_ERROR_CODE_ENCODING_FAILED diff --git a/main/streams/stream_errors_arginfo.h b/main/streams/stream_errors_arginfo.h index fde8805efd8e8..ff8da9dab548e 100644 --- a/main/streams/stream_errors_arginfo.h +++ b/main/streams/stream_errors_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 33e2f6f12083668388d80dbd77d97fd3f1efbe39 */ + * Stub hash: e3d25328018715348be75f6cb31ae6684afe0a56 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_StreamException_getParam, 0, 0, IS_STRING, 1) ZEND_END_ARG_INFO() @@ -33,6 +33,8 @@ static void register_stream_errors_symbols(int module_number) REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_ALREADY_EXISTS", STREAM_ERROR_CODE_ALREADY_EXISTS, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_INVALID_PATH", STREAM_ERROR_CODE_INVALID_PATH, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_PATH_TOO_LONG", STREAM_ERROR_CODE_PATH_TOO_LONG, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_CREATE_FAILED", STREAM_ERROR_CODE_CREATE_FAILED, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_OPEN_FAILED", STREAM_ERROR_CODE_OPEN_FAILED, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_UNLINK_FAILED", STREAM_ERROR_CODE_UNLINK_FAILED, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_RENAME_FAILED", STREAM_ERROR_CODE_RENAME_FAILED, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_MKDIR_FAILED", STREAM_ERROR_CODE_MKDIR_FAILED, CONST_PERSISTENT); @@ -60,6 +62,7 @@ static void register_stream_errors_symbols(int module_number) REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_NETWORK_SEND_FAILED", STREAM_ERROR_CODE_NETWORK_SEND_FAILED, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_NETWORK_RECV_FAILED", STREAM_ERROR_CODE_NETWORK_RECV_FAILED, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_SSL_NOT_SUPPORTED", STREAM_ERROR_CODE_SSL_NOT_SUPPORTED, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_RESUMPTION_FAILED", STREAM_ERROR_CODE_RESUMPTION_FAILED, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_SOCKET_PATH_TOO_LONG", STREAM_ERROR_CODE_SOCKET_PATH_TOO_LONG, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_OOB_NOT_SUPPORTED", STREAM_ERROR_CODE_OOB_NOT_SUPPORTED, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_PROTOCOL_ERROR", STREAM_ERROR_CODE_PROTOCOL_ERROR, CONST_PERSISTENT); @@ -67,6 +70,7 @@ static void register_stream_errors_symbols(int module_number) REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_INVALID_RESPONSE", STREAM_ERROR_CODE_INVALID_RESPONSE, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_REDIRECT_LIMIT", STREAM_ERROR_CODE_REDIRECT_LIMIT, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_AUTH_FAILED", STREAM_ERROR_CODE_AUTH_FAILED, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_ARCHIVING_FAILED", STREAM_ERROR_CODE_ARCHIVING_FAILED, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_ENCODING_FAILED", STREAM_ERROR_CODE_ENCODING_FAILED, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_INVALID_FORMAT", STREAM_ERROR_CODE_INVALID_FORMAT, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_ALLOCATION_FAILED", STREAM_ERROR_CODE_ALLOCATION_FAILED, CONST_PERSISTENT); From 1767a7d52c01e727841bedf0cd355d812538bff4 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Sun, 16 Nov 2025 18:24:22 +0100 Subject: [PATCH 06/68] stream: convert http wrapper errors --- ext/standard/http_fopen_wrapper.c | 49 ++++++++++++++++++---------- main/streams/php_stream_errors.h | 6 ++-- main/streams/stream_errors.stub.php | 10 ++++++ main/streams/stream_errors_arginfo.h | 4 ++- 4 files changed, 48 insertions(+), 21 deletions(-) diff --git a/ext/standard/http_fopen_wrapper.c b/ext/standard/http_fopen_wrapper.c index 1891347e2a66b..48d4fb65b13ce 100644 --- a/ext/standard/http_fopen_wrapper.c +++ b/ext/standard/http_fopen_wrapper.c @@ -245,7 +245,7 @@ static zend_string *php_stream_http_response_headers_parse(php_stream_wrapper *w while (last_header_name < last_header_value) { if (*last_header_name == ' ' || *last_header_name == '\t') { header_info->error = true; - php_stream_wrapper_log_error(wrapper, options, + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_INVALID_RESPONSE, "HTTP invalid response format (space in header name)!"); zend_string_efree(last_header_line_str); return NULL; @@ -263,7 +263,7 @@ static zend_string *php_stream_http_response_headers_parse(php_stream_wrapper *w } else { /* There is no colon which means invalid response so error. */ header_info->error = true; - php_stream_wrapper_log_error(wrapper, options, + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_INVALID_RESPONSE, "HTTP invalid response format (no colon in header line)!"); zend_string_efree(last_header_line_str); return NULL; @@ -287,7 +287,7 @@ static zend_string *php_stream_http_response_headers_parse(php_stream_wrapper *w size_t last_header_value_len = strlen(last_header_value); if (last_header_value_len > HTTP_HEADER_MAX_LOCATION_SIZE) { header_info->error = true; - php_stream_wrapper_log_error(wrapper, options, + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_INVALID_RESPONSE, "HTTP Location header size is over the limit of %d bytes", HTTP_HEADER_MAX_LOCATION_SIZE); zend_string_efree(last_header_line_str); @@ -388,7 +388,8 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, tmp_line[0] = '\0'; if (redirect_max < 1) { - php_stream_wrapper_log_error(wrapper, options, "Redirection limit reached, aborting"); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_REDIRECT_LIMIT, + "Redirection limit reached, aborting"); return NULL; } @@ -421,7 +422,8 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, /* Normal http request (possibly with proxy) */ if (strpbrk(mode, "awx+")) { - php_stream_wrapper_log_error(wrapper, options, "HTTP wrapper does not support writeable connections"); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_MODE_NOT_SUPPORTED, + "HTTP wrapper does not support writeable connections"); php_uri_struct_free(resource); return NULL; } @@ -450,7 +452,8 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, } if (request_fulluri && (strchr(path, '\n') != NULL || strchr(path, '\r') != NULL)) { - php_stream_wrapper_log_error(wrapper, options, "HTTP wrapper full URI path does not allow CR or LF characters"); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_INVALID_URL, + "HTTP wrapper full URI path does not allow CR or LF characters"); php_uri_struct_free(resource); zend_string_release(transport_string); return NULL; @@ -465,7 +468,8 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, #endif if (d > timeoutmax) { - php_stream_wrapper_log_error(wrapper, options, "timeout must be lower than " ZEND_ULONG_FMT, (zend_ulong)timeoutmax); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_INVALID_PARAM, + "timeout must be lower than " ZEND_ULONG_FMT, (zend_ulong)timeoutmax); zend_string_release(transport_string); php_uri_struct_free(resource); return NULL; @@ -495,7 +499,8 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, } if (errstr) { - php_stream_wrapper_log_error(wrapper, options, "%s", ZSTR_VAL(errstr)); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_PROTOCOL_ERROR, + "%s", ZSTR_VAL(errstr)); zend_string_release_ex(errstr, 0); errstr = NULL; } @@ -546,7 +551,8 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, smart_str_appendl(&header, "\r\n", sizeof("\r\n")-1); if (php_stream_write(stream, ZSTR_VAL(header.s), ZSTR_LEN(header.s)) != ZSTR_LEN(header.s)) { - php_stream_wrapper_log_error(wrapper, options, "Cannot connect to HTTPS server through proxy"); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_PROTOCOL_ERROR, + "Cannot connect to HTTPS server through proxy"); php_stream_close(stream); stream = NULL; } @@ -569,7 +575,8 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, if (stream) { if (php_stream_xport_crypto_setup(stream, STREAM_CRYPTO_METHOD_SSLv23_CLIENT, NULL) < 0 || php_stream_xport_crypto_enable(stream, 1) < 0) { - php_stream_wrapper_log_error(wrapper, options, "Cannot connect to HTTPS server through proxy"); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_SSL_NOT_SUPPORTED, + "Cannot connect to HTTPS server through proxy"); php_stream_close(stream); stream = NULL; } @@ -826,7 +833,8 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, ua[ua_len] = 0; smart_str_appendl(&req_buf, ua, ua_len); } else { - php_error_docref(NULL, E_WARNING, "Cannot construct User-agent header"); + php_stream_wrapper_warn_nt(wrapper, context, options, STREAM_ERROR_CODE_INVALID_HEADER, + "Cannot construct User-agent header"); } efree(ua); } @@ -865,7 +873,8 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, } if (!(have_header & HTTP_HEADER_TYPE)) { smart_str_appends(&req_buf, "Content-Type: application/x-www-form-urlencoded\r\n"); - php_error_docref(NULL, E_NOTICE, "Content-type not specified assuming application/x-www-form-urlencoded"); + php_stream_wrapper_notice(wrapper, context, options, STREAM_ERROR_CODE_INVALID_HEADER, + "Content-type not specified assuming application/x-www-form-urlencoded"); } smart_str_appends(&req_buf, "\r\n"); smart_str_append(&req_buf, Z_STR_P(tmpzval)); @@ -952,7 +961,8 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, } else { php_stream_close(stream); stream = NULL; - php_stream_wrapper_log_error(wrapper, options, "HTTP request failed!"); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_PROTOCOL_ERROR, + "HTTP request failed!"); goto out; } } @@ -970,7 +980,7 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, if (http_header_line[1] != '\n') { php_stream_close(stream); stream = NULL; - php_stream_wrapper_log_error(wrapper, options, + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_INVALID_RESPONSE, "HTTP invalid header name (cannot start with CR character)!"); goto out; } @@ -1001,7 +1011,7 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, if (*http_header_line == ' ' || *http_header_line == '\t') { php_stream_close(stream); stream = NULL; - php_stream_wrapper_log_error(wrapper, options, + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_INVALID_RESPONSE, "HTTP invalid response format (folding header at the start)!"); goto out; } @@ -1097,7 +1107,8 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, php_uri_struct_free(resource); /* check for invalid redirection URLs */ if ((resource = php_uri_parse_to_struct(uri_parser, new_path, strlen(new_path), PHP_URI_COMPONENT_READ_MODE_RAW, true)) == NULL) { - php_stream_wrapper_log_error(wrapper, options, "Invalid redirect URL! %s", new_path); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_INVALID_URL, + "Invalid redirect URL! %s", new_path); efree(new_path); goto out; } @@ -1109,7 +1120,8 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, s = (unsigned char*)ZSTR_VAL(val); e = s + ZSTR_LEN(val); \ while (s < e) { \ if (iscntrl(*s)) { \ - php_stream_wrapper_log_error(wrapper, options, "Invalid redirect URL! %s", new_path); \ + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_INVALID_URL, \ + "Invalid redirect URL! %s", new_path); \ efree(new_path); \ goto out; \ } \ @@ -1135,7 +1147,8 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, --redirect_max, new_flags, response_header STREAMS_CC); efree(new_path); } else { - php_stream_wrapper_log_error(wrapper, options, "HTTP request failed! %s", tmp_line); + php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_PROTOCOL_ERROR, + "HTTP request failed! %s", tmp_line); } } out: diff --git a/main/streams/php_stream_errors.h b/main/streams/php_stream_errors.h index f36ece142bc06..2d77c17864db5 100644 --- a/main/streams/php_stream_errors.h +++ b/main/streams/php_stream_errors.h @@ -93,8 +93,10 @@ BEGIN_EXTERN_C() #define STREAM_ERROR_CODE_PROTOCOL_ERROR 106 #define STREAM_ERROR_CODE_INVALID_URL 107 #define STREAM_ERROR_CODE_INVALID_RESPONSE 108 -#define STREAM_ERROR_CODE_REDIRECT_LIMIT 109 -#define STREAM_ERROR_CODE_AUTH_FAILED 110 +#define STREAM_ERROR_CODE_INVALID_HEADER 109 +#define STREAM_ERROR_CODE_INVALID_PARAM 110 +#define STREAM_ERROR_CODE_REDIRECT_LIMIT 111 +#define STREAM_ERROR_CODE_AUTH_FAILED 112 /* Encoding/decoding/archiving operations */ #define STREAM_ERROR_CODE_ARCHIVING_FAILED 120 #define STREAM_ERROR_CODE_ENCODING_FAILED 121 diff --git a/main/streams/stream_errors.stub.php b/main/streams/stream_errors.stub.php index a9d090858aff6..7e76865b02a62 100644 --- a/main/streams/stream_errors.stub.php +++ b/main/streams/stream_errors.stub.php @@ -261,6 +261,16 @@ public function getWrapperName(): string {} * @cvalue STREAM_ERROR_CODE_INVALID_RESPONSE */ const STREAM_ERROR_CODE_INVALID_RESPONSE = UNKNOWN; +/** + * @var int + * @cvalue STREAM_ERROR_CODE_INVALID_HEADER + */ +const STREAM_ERROR_CODE_INVALID_HEADER = UNKNOWN; +/** + * @var int + * @cvalue STREAM_ERROR_CODE_INVALID_PARAM + */ +const STREAM_ERROR_CODE_INVALID_PARAM = UNKNOWN; /** * @var int * @cvalue STREAM_ERROR_CODE_REDIRECT_LIMIT diff --git a/main/streams/stream_errors_arginfo.h b/main/streams/stream_errors_arginfo.h index ff8da9dab548e..dd2051c0e10df 100644 --- a/main/streams/stream_errors_arginfo.h +++ b/main/streams/stream_errors_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: e3d25328018715348be75f6cb31ae6684afe0a56 */ + * Stub hash: c40a28ed8224ab9fc3673ca4dec0d5376f9acd7e */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_StreamException_getParam, 0, 0, IS_STRING, 1) ZEND_END_ARG_INFO() @@ -68,6 +68,8 @@ static void register_stream_errors_symbols(int module_number) REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_PROTOCOL_ERROR", STREAM_ERROR_CODE_PROTOCOL_ERROR, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_INVALID_URL", STREAM_ERROR_CODE_INVALID_URL, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_INVALID_RESPONSE", STREAM_ERROR_CODE_INVALID_RESPONSE, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_INVALID_HEADER", STREAM_ERROR_CODE_INVALID_HEADER, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_INVALID_PARAM", STREAM_ERROR_CODE_INVALID_PARAM, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_REDIRECT_LIMIT", STREAM_ERROR_CODE_REDIRECT_LIMIT, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_AUTH_FAILED", STREAM_ERROR_CODE_AUTH_FAILED, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_ARCHIVING_FAILED", STREAM_ERROR_CODE_ARCHIVING_FAILED, CONST_PERSISTENT); From d5e246ca61a1c60bb60a801fc0fa31c27baa30c9 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Sun, 16 Nov 2025 18:46:22 +0100 Subject: [PATCH 07/68] stream: add context param to php_stream_wrapper_log_* variants --- ext/phar/dirstream.c | 54 +++++++++++++++---------------- ext/phar/stream.c | 48 +++++++++++++-------------- ext/standard/ftp_fopen_wrapper.c | 26 +++++++-------- ext/standard/http_fopen_wrapper.c | 20 ++++++------ main/streams/php_stream_errors.h | 18 ++++++----- main/streams/stream_errors.c | 22 ++++++------- 6 files changed, 93 insertions(+), 95 deletions(-) diff --git a/ext/phar/dirstream.c b/ext/phar/dirstream.c index 7faeddba25d7d..6ea3f7ba2fb06 100644 --- a/ext/phar/dirstream.c +++ b/ext/phar/dirstream.c @@ -254,7 +254,7 @@ php_stream *phar_wrapper_open_dir(php_stream_wrapper *wrapper, const char *path, phar_archive_data *phar; if ((resource = phar_parse_url(wrapper, path, mode, options)) == NULL) { - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_INVALID_URL, + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_INVALID_URL, "phar url \"%s\" is unknown", path); return NULL; } @@ -262,21 +262,21 @@ php_stream *phar_wrapper_open_dir(php_stream_wrapper *wrapper, const char *path, /* we must have at the very least phar://alias.phar/ */ if (!resource->scheme || !resource->host || !resource->path) { if (resource->host && !resource->path) { - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_INVALID_PATH, + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_INVALID_PATH, "phar error: no directory in \"%s\", must have at least phar://%s/ for root directory (always use full path to a new phar)", path, ZSTR_VAL(resource->host)); php_url_free(resource); return NULL; } php_url_free(resource); - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_INVALID_URL, + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_INVALID_URL, "phar error: invalid url \"%s\", must have at least phar://%s/", path, path); return NULL; } if (!zend_string_equals_literal_ci(resource->scheme, "phar")) { php_url_free(resource); - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_PROTOCOL_UNSUPPORTED, + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_PROTOCOL_UNSUPPORTED, "phar error: not a phar url \"%s\"", path); return NULL; } @@ -285,10 +285,10 @@ php_stream *phar_wrapper_open_dir(php_stream_wrapper *wrapper, const char *path, if (FAILURE == phar_get_archive(&phar, ZSTR_VAL(resource->host), ZSTR_LEN(resource->host), NULL, 0, &error)) { if (error) { - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_NOT_FOUND, "%s", error); + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_NOT_FOUND, "%s", error); efree(error); } else { - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_NOT_FOUND, + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_NOT_FOUND, "phar file \"%s\" is unknown", ZSTR_VAL(resource->host)); } php_url_free(resource); @@ -359,7 +359,7 @@ int phar_wrapper_mkdir(php_stream_wrapper *wrapper, const char *url_from, int mo /* pre-readonly check, we need to know if this is a data phar */ if (FAILURE == phar_split_fname(url_from, strlen(url_from), &arch, &arch_len, NULL, NULL, 2, 2)) { - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_NOT_FOUND, + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_NOT_FOUND, "phar error: cannot create directory \"%s\", no phar archive specified", url_from); return 0; } @@ -371,7 +371,7 @@ int phar_wrapper_mkdir(php_stream_wrapper *wrapper, const char *url_from, int mo efree(arch); if (PHAR_G(readonly) && (!phar || !phar->is_data)) { - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_READONLY, + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_READONLY, "phar error: cannot create directory \"%s\", write operations disabled", url_from); return 0; } @@ -383,20 +383,20 @@ int phar_wrapper_mkdir(php_stream_wrapper *wrapper, const char *url_from, int mo /* we must have at the very least phar://alias.phar/internalfile.php */ if (!resource->scheme || !resource->host || !resource->path) { php_url_free(resource); - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_INVALID_URL, + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_INVALID_URL, "phar error: invalid url \"%s\"", url_from); return 0; } if (!zend_string_equals_literal_ci(resource->scheme, "phar")) { php_url_free(resource); - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_PROTOCOL_UNSUPPORTED, + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_PROTOCOL_UNSUPPORTED, "phar error: not a phar stream url \"%s\"", url_from); return 0; } if (FAILURE == phar_get_archive(&phar, ZSTR_VAL(resource->host), ZSTR_LEN(resource->host), NULL, 0, &error)) { - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_MKDIR_FAILED, + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_MKDIR_FAILED, "phar error: cannot create directory \"%s\" in phar \"%s\", error retrieving phar information: %s", ZSTR_VAL(resource->path) + 1, ZSTR_VAL(resource->host), error); efree(error); @@ -410,7 +410,7 @@ int phar_wrapper_mkdir(php_stream_wrapper *wrapper, const char *url_from, int mo zend_string_efree(e->filename); efree(e); } - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_ALREADY_EXISTS, + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_ALREADY_EXISTS, "phar error: cannot create directory \"%s\" in phar \"%s\", directory already exists", ZSTR_VAL(resource->path)+1, ZSTR_VAL(resource->host)); php_url_free(resource); @@ -418,7 +418,7 @@ int phar_wrapper_mkdir(php_stream_wrapper *wrapper, const char *url_from, int mo } if (error) { - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_MKDIR_FAILED, + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_MKDIR_FAILED, "phar error: cannot create directory \"%s\" in phar \"%s\", %s", ZSTR_VAL(resource->path)+1, ZSTR_VAL(resource->host), error); efree(error); @@ -428,7 +428,7 @@ int phar_wrapper_mkdir(php_stream_wrapper *wrapper, const char *url_from, int mo if (phar_get_entry_info_dir(phar, ZSTR_VAL(resource->path) + 1, ZSTR_LEN(resource->path) - 1, 0, &error, true)) { /* entry exists as a file */ - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_ALREADY_EXISTS, + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_ALREADY_EXISTS, "phar error: cannot create directory \"%s\" in phar \"%s\", file already exists", ZSTR_VAL(resource->path)+1, ZSTR_VAL(resource->host)); php_url_free(resource); @@ -436,7 +436,7 @@ int phar_wrapper_mkdir(php_stream_wrapper *wrapper, const char *url_from, int mo } if (error) { - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_MKDIR_FAILED, + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_MKDIR_FAILED, "phar error: cannot create directory \"%s\" in phar \"%s\", %s", ZSTR_VAL(resource->path)+1, ZSTR_VAL(resource->host), error); efree(error); @@ -467,7 +467,7 @@ int phar_wrapper_mkdir(php_stream_wrapper *wrapper, const char *url_from, int mo entry.old_flags = PHAR_ENT_PERM_DEF_DIR; if (NULL == zend_hash_add_mem(&phar->manifest, entry.filename, &entry, sizeof(phar_entry_info))) { - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_MKDIR_FAILED, + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_MKDIR_FAILED, "phar error: cannot create directory \"%s\" in phar \"%s\", adding to manifest failed", ZSTR_VAL(entry.filename), phar->fname); zend_string_efree(entry.filename); @@ -477,7 +477,7 @@ int phar_wrapper_mkdir(php_stream_wrapper *wrapper, const char *url_from, int mo phar_flush(phar, &error); if (error) { - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_MKDIR_FAILED, + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_MKDIR_FAILED, "phar error: cannot create directory \"%s\" in phar \"%s\", %s", ZSTR_VAL(entry.filename), phar->fname, error); zend_hash_del(&phar->manifest, entry.filename); @@ -503,7 +503,7 @@ int phar_wrapper_rmdir(php_stream_wrapper *wrapper, const char *url, int options /* pre-readonly check, we need to know if this is a data phar */ if (FAILURE == phar_split_fname(url, strlen(url), &arch, &arch_len, NULL, NULL, 2, 2)) { - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_NOT_FOUND, + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_NOT_FOUND, "phar error: cannot remove directory \"%s\", no phar archive specified, or phar archive does not exist", url); return 0; } @@ -515,7 +515,7 @@ int phar_wrapper_rmdir(php_stream_wrapper *wrapper, const char *url, int options efree(arch); if (PHAR_G(readonly) && (!phar || !phar->is_data)) { - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_READONLY, + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_READONLY, "phar error: cannot rmdir directory \"%s\", write operations disabled", url); return 0; } @@ -527,20 +527,20 @@ int phar_wrapper_rmdir(php_stream_wrapper *wrapper, const char *url, int options /* we must have at the very least phar://alias.phar/internalfile.php */ if (!resource->scheme || !resource->host || !resource->path) { php_url_free(resource); - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_INVALID_URL, + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_INVALID_URL, "phar error: invalid url \"%s\"", url); return 0; } if (!zend_string_equals_literal_ci(resource->scheme, "phar")) { php_url_free(resource); - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_PROTOCOL_UNSUPPORTED, + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_PROTOCOL_UNSUPPORTED, "phar error: not a phar stream url \"%s\"", url); return 0; } if (FAILURE == phar_get_archive(&phar, ZSTR_VAL(resource->host), ZSTR_LEN(resource->host), NULL, 0, &error)) { - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_RMDIR_FAILED, + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_RMDIR_FAILED, "phar error: cannot remove directory \"%s\" in phar \"%s\", error retrieving phar information: %s", ZSTR_VAL(resource->path)+1, ZSTR_VAL(resource->host), error); efree(error); @@ -552,12 +552,12 @@ int phar_wrapper_rmdir(php_stream_wrapper *wrapper, const char *url, int options if (!(entry = phar_get_entry_info_dir(phar, ZSTR_VAL(resource->path) + 1, path_len, 2, &error, true))) { if (error) { - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_RMDIR_FAILED, + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_RMDIR_FAILED, "phar error: cannot remove directory \"%s\" in phar \"%s\", %s", ZSTR_VAL(resource->path)+1, ZSTR_VAL(resource->host), error); efree(error); } else { - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_NOT_FOUND, + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_NOT_FOUND, "phar error: cannot remove directory \"%s\" in phar \"%s\", directory does not exist", ZSTR_VAL(resource->path)+1, ZSTR_VAL(resource->host)); } @@ -573,7 +573,7 @@ int phar_wrapper_rmdir(php_stream_wrapper *wrapper, const char *url, int options zend_string_starts_with_cstr(str_key, ZSTR_VAL(resource->path)+1, path_len) && IS_SLASH(ZSTR_VAL(str_key)[path_len]) ) { - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_RMDIR_FAILED, + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_RMDIR_FAILED, "phar error: Directory not empty"); if (entry->is_temp_dir) { zend_string_efree(entry->filename); @@ -590,7 +590,7 @@ int phar_wrapper_rmdir(php_stream_wrapper *wrapper, const char *url, int options zend_string_starts_with_cstr(str_key, ZSTR_VAL(resource->path)+1, path_len) && IS_SLASH(ZSTR_VAL(str_key)[path_len]) ) { - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_RMDIR_FAILED, + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_RMDIR_FAILED, "phar error: Directory not empty"); if (entry->is_temp_dir) { zend_string_efree(entry->filename); @@ -612,7 +612,7 @@ int phar_wrapper_rmdir(php_stream_wrapper *wrapper, const char *url, int options phar_flush(phar, &error); if (error) { - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_RMDIR_FAILED, + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_RMDIR_FAILED, "phar error: cannot remove directory \"%s\" in phar \"%s\", %s", ZSTR_VAL(entry->filename), phar->fname, error); php_url_free(resource); diff --git a/ext/phar/stream.c b/ext/phar/stream.c index f8575a499407a..98e8a3322c488 100644 --- a/ext/phar/stream.c +++ b/ext/phar/stream.c @@ -68,7 +68,7 @@ php_url* phar_parse_url(php_stream_wrapper *wrapper, const char *filename, const } if (mode[0] == 'a') { if (!(options & PHP_STREAM_URL_STAT_QUIET)) { - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_MODE_NOT_SUPPORTED, + php_stream_wrapper_log_warn(wrapper, NULL, options, STREAM_ERROR_CODE_MODE_NOT_SUPPORTED, "phar error: open mode append not supported"); } return NULL; @@ -76,12 +76,12 @@ php_url* phar_parse_url(php_stream_wrapper *wrapper, const char *filename, const if (phar_split_fname(filename, strlen(filename), &arch, &arch_len, &entry, &entry_len, 2, (mode[0] == 'w' ? 2 : 0)) == FAILURE) { if (!(options & PHP_STREAM_URL_STAT_QUIET)) { if (arch && !entry) { - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_INVALID_PATH, + php_stream_wrapper_log_warn(wrapper, NULL, options, STREAM_ERROR_CODE_INVALID_PATH, "phar error: no directory in \"%s\", must have at least phar://%s/ for root directory (always use full path to a new phar)", filename, arch); arch = NULL; } else { - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_INVALID_URL, + php_stream_wrapper_log_warn(wrapper, NULL, options, STREAM_ERROR_CODE_INVALID_URL, "phar error: invalid url or non-existent phar \"%s\"", filename); } } @@ -115,7 +115,7 @@ php_url* phar_parse_url(php_stream_wrapper *wrapper, const char *filename, const } if (PHAR_G(readonly) && (!pphar || !pphar->is_data)) { if (!(options & PHP_STREAM_URL_STAT_QUIET)) { - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_READONLY, + php_stream_wrapper_log_warn(wrapper, NULL, options, STREAM_ERROR_CODE_READONLY, "phar error: write operations disabled by the php.ini setting phar.readonly"); } php_url_free(resource); @@ -125,7 +125,7 @@ php_url* phar_parse_url(php_stream_wrapper *wrapper, const char *filename, const { if (error) { if (!(options & PHP_STREAM_URL_STAT_QUIET)) { - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_OPEN_FAILED, "%s", error); + php_stream_wrapper_log_warn(wrapper, NULL, options, STREAM_ERROR_CODE_OPEN_FAILED, "%s", error); } efree(error); } @@ -136,7 +136,7 @@ php_url* phar_parse_url(php_stream_wrapper *wrapper, const char *filename, const if (error) { spprintf(&error, 0, "Cannot open cached phar '%s' as writeable, copy on write failed", ZSTR_VAL(resource->host)); if (!(options & PHP_STREAM_URL_STAT_QUIET)) { - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_OPEN_FAILED, "%s", error); + php_stream_wrapper_log_warn(wrapper, NULL, options, STREAM_ERROR_CODE_OPEN_FAILED, "%s", error); } efree(error); } @@ -148,7 +148,7 @@ php_url* phar_parse_url(php_stream_wrapper *wrapper, const char *filename, const { if (error) { if (!(options & PHP_STREAM_URL_STAT_QUIET)) { - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_NOT_FOUND, "%s", error); + php_stream_wrapper_log_warn(wrapper, NULL, options, STREAM_ERROR_CODE_NOT_FOUND, "%s", error); } efree(error); } @@ -181,14 +181,14 @@ static php_stream * phar_wrapper_open_url(php_stream_wrapper *wrapper, const cha /* we must have at the very least phar://alias.phar/internalfile.php */ if (!resource->scheme || !resource->host || !resource->path) { php_url_free(resource); - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_INVALID_URL, + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_INVALID_URL, "phar error: invalid url \"%s\"", path); return NULL; } if (!zend_string_equals_literal_ci(resource->scheme, "phar")) { php_url_free(resource); - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_PROTOCOL_UNSUPPORTED, + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_PROTOCOL_UNSUPPORTED, "phar error: not a phar stream url \"%s\"", path); return NULL; } @@ -200,10 +200,10 @@ static php_stream * phar_wrapper_open_url(php_stream_wrapper *wrapper, const cha if (mode[0] == 'w' || (mode[0] == 'r' && mode[1] == '+')) { if (NULL == (idata = phar_get_or_create_entry_data(ZSTR_VAL(resource->host), ZSTR_LEN(resource->host), internal_file, strlen(internal_file), mode, 0, &error, true, time(NULL)))) { if (error) { - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_CREATE_FAILED, "%s", error); + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_CREATE_FAILED, "%s", error); efree(error); } else { - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_CREATE_FAILED, + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_CREATE_FAILED, "phar error: file \"%s\" could not be created in phar \"%s\"", internal_file, ZSTR_VAL(resource->host)); } efree(internal_file); @@ -244,7 +244,7 @@ static php_stream * phar_wrapper_open_url(php_stream_wrapper *wrapper, const cha if (!*internal_file && (options & STREAM_OPEN_FOR_INCLUDE)) { /* retrieve the stub */ if (FAILURE == phar_get_archive(&phar, ZSTR_VAL(resource->host), ZSTR_LEN(resource->host), NULL, 0, NULL)) { - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_INVALID_FORMAT, + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_INVALID_FORMAT, "file %s is not a valid phar archive", ZSTR_VAL(resource->host)); efree(internal_file); php_url_free(resource); @@ -265,7 +265,7 @@ static php_stream * phar_wrapper_open_url(php_stream_wrapper *wrapper, const cha if (stream == NULL) { stream = phar_open_archive_fp(phar); if (UNEXPECTED(!stream)) { - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_OPEN_FAILED, + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_OPEN_FAILED, "phar error: could not reopen phar \"%s\"", ZSTR_VAL(resource->host)); efree(internal_file); php_url_free(resource); @@ -303,10 +303,10 @@ static php_stream * phar_wrapper_open_url(php_stream_wrapper *wrapper, const cha if ((FAILURE == phar_get_entry_data(&idata, ZSTR_VAL(resource->host), ZSTR_LEN(resource->host), internal_file, strlen(internal_file), "r", 0, &error, false)) || !idata) { idata_error: if (error) { - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_NOT_FOUND, "%s", error); + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_NOT_FOUND, "%s", error); efree(error); } else { - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_NOT_FOUND, + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_NOT_FOUND, "phar error: \"%s\" is not a file in phar \"%s\"", internal_file, ZSTR_VAL(resource->host)); } efree(internal_file); @@ -325,7 +325,7 @@ static php_stream * phar_wrapper_open_url(php_stream_wrapper *wrapper, const cha /* check length, crc32 */ if (!idata->internal_file->is_crc_checked && phar_postprocess_file(idata, idata->internal_file->crc32, &error, 2) != SUCCESS) { - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_ARCHIVING_FAILED, "%s", error); + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_ARCHIVING_FAILED, "%s", error); efree(error); phar_entry_delref(idata); efree(internal_file); @@ -678,7 +678,7 @@ static int phar_wrapper_unlink(php_stream_wrapper *wrapper, const char *url, int phar_archive_data *pphar; if ((resource = phar_parse_url(wrapper, url, "rb", options)) == NULL) { - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_UNLINK_FAILED, + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_UNLINK_FAILED, "phar error: unlink failed"); return 0; } @@ -686,14 +686,14 @@ static int phar_wrapper_unlink(php_stream_wrapper *wrapper, const char *url, int /* we must have at the very least phar://alias.phar/internalfile.php */ if (!resource->scheme || !resource->host || !resource->path) { php_url_free(resource); - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_INVALID_URL, + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_INVALID_URL, "phar error: invalid url \"%s\"", url); return 0; } if (!zend_string_equals_literal_ci(resource->scheme, "phar")) { php_url_free(resource); - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_PROTOCOL_UNSUPPORTED, + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_PROTOCOL_UNSUPPORTED, "phar error: not a phar stream url \"%s\"", url); return 0; } @@ -703,7 +703,7 @@ static int phar_wrapper_unlink(php_stream_wrapper *wrapper, const char *url, int pphar = zend_hash_find_ptr(&(PHAR_G(phar_fname_map)), resource->host); if (PHAR_G(readonly) && (!pphar || !pphar->is_data)) { php_url_free(resource); - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_READONLY, + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_READONLY, "phar error: write operations disabled by the php.ini setting phar.readonly"); return 0; } @@ -714,11 +714,11 @@ static int phar_wrapper_unlink(php_stream_wrapper *wrapper, const char *url, int if (FAILURE == phar_get_entry_data(&idata, ZSTR_VAL(resource->host), ZSTR_LEN(resource->host), internal_file, internal_file_len, "r", 0, &error, true)) { /* constraints of fp refcount were not met */ if (error) { - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_UNLINK_FAILED, + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_UNLINK_FAILED, "unlink of \"%s\" failed: %s", url, error); efree(error); } else { - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_NOT_FOUND, + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_NOT_FOUND, "unlink of \"%s\" failed, file does not exist", url); } efree(internal_file); @@ -730,7 +730,7 @@ static int phar_wrapper_unlink(php_stream_wrapper *wrapper, const char *url, int } if (idata->internal_file->fp_refcount > 1) { /* more than just our fp resource is open for this file */ - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_UNLINK_FAILED, + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_UNLINK_FAILED, "phar error: \"%s\" in phar \"%s\", has open file pointers, cannot unlink", internal_file, ZSTR_VAL(resource->host)); efree(internal_file); @@ -742,7 +742,7 @@ static int phar_wrapper_unlink(php_stream_wrapper *wrapper, const char *url, int efree(internal_file); phar_entry_remove(idata, &error); if (error) { - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_UNLINK_FAILED, "%s", error); + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_UNLINK_FAILED, "%s", error); efree(error); } return 1; diff --git a/ext/standard/ftp_fopen_wrapper.c b/ext/standard/ftp_fopen_wrapper.c index 3c5a490660c8d..49352ae4a4cbe 100644 --- a/ext/standard/ftp_fopen_wrapper.c +++ b/ext/standard/ftp_fopen_wrapper.c @@ -188,7 +188,7 @@ static php_stream *php_ftp_fopen_connect(php_stream_wrapper *wrapper, const char /* get the response */ result = GET_FTP_RESULT(stream); if (result != 334) { - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_SSL_NOT_SUPPORTED, + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_SSL_NOT_SUPPORTED, "Server doesn't support FTPS."); goto connect_errexit; } else { @@ -208,7 +208,7 @@ static php_stream *php_ftp_fopen_connect(php_stream_wrapper *wrapper, const char if (php_stream_xport_crypto_setup(stream, STREAM_CRYPTO_METHOD_SSLv23_CLIENT, NULL) < 0 || php_stream_xport_crypto_enable(stream, 1) < 0) { - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_SSL_NOT_SUPPORTED, + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_SSL_NOT_SUPPORTED, "Unable to activate SSL mode"); php_stream_close(stream); stream = NULL; @@ -240,7 +240,7 @@ static php_stream *php_ftp_fopen_connect(php_stream_wrapper *wrapper, const char unsigned char *s = (unsigned char *) val, *e = (unsigned char *) s + val_len; \ while (s < e) { \ if (iscntrl(*s)) { \ - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_AUTH_FAILED, err_msg, val); \ + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_AUTH_FAILED, err_msg, val); \ goto connect_errexit; \ } \ s++; \ @@ -437,7 +437,7 @@ php_stream * php_stream_url_wrap_ftp(php_stream_wrapper *wrapper, const char *pa } if (strpbrk(mode, "wa+")) { if (read_write) { - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_MODE_NOT_SUPPORTED, + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_MODE_NOT_SUPPORTED, "FTP does not support simultaneous read/write connections"); return NULL; } @@ -449,7 +449,7 @@ php_stream * php_stream_url_wrap_ftp(php_stream_wrapper *wrapper, const char *pa } if (!read_write) { /* No mode specified? */ - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_INVALID_MODE, + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_INVALID_MODE, "Unknown file open mode"); return NULL; } @@ -461,7 +461,7 @@ php_stream * php_stream_url_wrap_ftp(php_stream_wrapper *wrapper, const char *pa return php_stream_url_wrap_http(wrapper, path, mode, options, opened_path, context STREAMS_CC); } else { /* ftp proxy is read-only */ - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_MODE_NOT_SUPPORTED, + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_MODE_NOT_SUPPORTED, "FTP proxy may only be used in read mode"); return NULL; } @@ -514,7 +514,7 @@ php_stream * php_stream_url_wrap_ftp(php_stream_wrapper *wrapper, const char *pa goto errexit; } } else { - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_ALREADY_EXISTS, + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_ALREADY_EXISTS, "Remote file already exists and overwrite context option not specified"); errno = EEXIST; goto errexit; @@ -539,7 +539,7 @@ php_stream * php_stream_url_wrap_ftp(php_stream_wrapper *wrapper, const char *pa php_stream_printf(stream, "REST " ZEND_LONG_FMT "\r\n", Z_LVAL_P(tmpzval)); result = GET_FTP_RESULT(stream); if (result < 300 || result > 399) { - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_RESUMPTION_FAILED, + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_RESUMPTION_FAILED, "Unable to resume from offset " ZEND_LONG_FMT, Z_LVAL_P(tmpzval)); goto errexit; } @@ -585,7 +585,7 @@ php_stream * php_stream_url_wrap_ftp(php_stream_wrapper *wrapper, const char *pa STREAM_CRYPTO_METHOD_SSLv23_CLIENT, NULL) < 0 || php_stream_xport_crypto_enable(datastream, 1) < 0)) { - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_SSL_NOT_SUPPORTED, + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_SSL_NOT_SUPPORTED, "Unable to activate SSL mode"); php_stream_close(datastream); datastream = NULL; @@ -608,11 +608,11 @@ php_stream * php_stream_url_wrap_ftp(php_stream_wrapper *wrapper, const char *pa php_stream_close(stream); } if (tmp_line[0] != '\0') - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_PROTOCOL_ERROR, + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_PROTOCOL_ERROR, "FTP server reports %s", tmp_line); if (error_message) { - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_NETWORK_SEND_FAILED, + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_NETWORK_SEND_FAILED, "Failed to set up data channel: %s", ZSTR_VAL(error_message)); zend_string_release(error_message); } @@ -758,7 +758,7 @@ static php_stream * php_stream_ftp_opendir(php_stream_wrapper *wrapper, const ch STREAM_CRYPTO_METHOD_SSLv23_CLIENT, NULL) < 0 || php_stream_xport_crypto_enable(datastream, 1) < 0)) { - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_SSL_NOT_SUPPORTED, + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_SSL_NOT_SUPPORTED, "Unable to activate SSL mode"); php_stream_close(datastream); datastream = NULL; @@ -783,7 +783,7 @@ static php_stream * php_stream_ftp_opendir(php_stream_wrapper *wrapper, const ch php_stream_close(stream); } if (tmp_line[0] != '\0') { - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_PROTOCOL_ERROR, + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_PROTOCOL_ERROR, "FTP server reports %s", tmp_line); } return NULL; diff --git a/ext/standard/http_fopen_wrapper.c b/ext/standard/http_fopen_wrapper.c index 48d4fb65b13ce..ed209bd7e90e7 100644 --- a/ext/standard/http_fopen_wrapper.c +++ b/ext/standard/http_fopen_wrapper.c @@ -245,7 +245,7 @@ static zend_string *php_stream_http_response_headers_parse(php_stream_wrapper *w while (last_header_name < last_header_value) { if (*last_header_name == ' ' || *last_header_name == '\t') { header_info->error = true; - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_INVALID_RESPONSE, + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_INVALID_RESPONSE, "HTTP invalid response format (space in header name)!"); zend_string_efree(last_header_line_str); return NULL; @@ -263,7 +263,7 @@ static zend_string *php_stream_http_response_headers_parse(php_stream_wrapper *w } else { /* There is no colon which means invalid response so error. */ header_info->error = true; - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_INVALID_RESPONSE, + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_INVALID_RESPONSE, "HTTP invalid response format (no colon in header line)!"); zend_string_efree(last_header_line_str); return NULL; @@ -388,7 +388,7 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, tmp_line[0] = '\0'; if (redirect_max < 1) { - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_REDIRECT_LIMIT, + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_REDIRECT_LIMIT, "Redirection limit reached, aborting"); return NULL; } @@ -422,7 +422,7 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, /* Normal http request (possibly with proxy) */ if (strpbrk(mode, "awx+")) { - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_MODE_NOT_SUPPORTED, + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_MODE_NOT_SUPPORTED, "HTTP wrapper does not support writeable connections"); php_uri_struct_free(resource); return NULL; @@ -452,7 +452,7 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, } if (request_fulluri && (strchr(path, '\n') != NULL || strchr(path, '\r') != NULL)) { - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_INVALID_URL, + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_INVALID_URL, "HTTP wrapper full URI path does not allow CR or LF characters"); php_uri_struct_free(resource); zend_string_release(transport_string); @@ -551,7 +551,7 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, smart_str_appendl(&header, "\r\n", sizeof("\r\n")-1); if (php_stream_write(stream, ZSTR_VAL(header.s), ZSTR_LEN(header.s)) != ZSTR_LEN(header.s)) { - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_PROTOCOL_ERROR, + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_PROTOCOL_ERROR, "Cannot connect to HTTPS server through proxy"); php_stream_close(stream); stream = NULL; @@ -575,7 +575,7 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, if (stream) { if (php_stream_xport_crypto_setup(stream, STREAM_CRYPTO_METHOD_SSLv23_CLIENT, NULL) < 0 || php_stream_xport_crypto_enable(stream, 1) < 0) { - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_SSL_NOT_SUPPORTED, + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_SSL_NOT_SUPPORTED, "Cannot connect to HTTPS server through proxy"); php_stream_close(stream); stream = NULL; @@ -961,7 +961,7 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, } else { php_stream_close(stream); stream = NULL; - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_PROTOCOL_ERROR, + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_PROTOCOL_ERROR, "HTTP request failed!"); goto out; } @@ -980,7 +980,7 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, if (http_header_line[1] != '\n') { php_stream_close(stream); stream = NULL; - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_INVALID_RESPONSE, + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_INVALID_RESPONSE, "HTTP invalid header name (cannot start with CR character)!"); goto out; } @@ -1011,7 +1011,7 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, if (*http_header_line == ' ' || *http_header_line == '\t') { php_stream_close(stream); stream = NULL; - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_INVALID_RESPONSE, + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_INVALID_RESPONSE, "HTTP invalid response format (folding header at the start)!"); goto out; } diff --git a/main/streams/php_stream_errors.h b/main/streams/php_stream_errors.h index 2d77c17864db5..1ed4257bf47e8 100644 --- a/main/streams/php_stream_errors.h +++ b/main/streams/php_stream_errors.h @@ -170,16 +170,18 @@ PHPAPI void php_stream_error( /* Legacy wrapper error log - updated API */ PHPAPI void php_stream_wrapper_log_error( const php_stream_wrapper *wrapper, + php_stream_context *context, int options, int severity, bool terminal, int code, const char *fmt, ... -) ZEND_ATTRIBUTE_FORMAT(printf, 6, 7); +) ZEND_ATTRIBUTE_FORMAT(printf, 7, 8); PHPAPI void php_stream_wrapper_log_error_param( const php_stream_wrapper *wrapper, + php_stream_context *context, int options, int severity, bool terminal, @@ -187,7 +189,7 @@ PHPAPI void php_stream_wrapper_log_error_param( const char *param, const char *fmt, ... -) ZEND_ATTRIBUTE_FORMAT(printf, 7, 8); +) ZEND_ATTRIBUTE_FORMAT(printf, 8, 9); PHPAPI void php_stream_display_wrapper_errors( php_stream_wrapper *wrapper, @@ -226,14 +228,14 @@ void php_stream_tidy_wrapper_error_log(php_stream_wrapper *wrapper); php_stream_error(stream, E_ERROR, true, code, __VA_ARGS__) /* Legacy log variants */ -#define php_stream_wrapper_log_warn(wrapper, options, code, ...) \ - php_stream_wrapper_log_error(wrapper, options, E_WARNING, true, code, __VA_ARGS__) +#define php_stream_wrapper_log_warn(wrapper, context, options, code, ...) \ + php_stream_wrapper_log_error(wrapper, context, options, E_WARNING, true, code, __VA_ARGS__) -#define php_stream_wrapper_log_warn_nt(wrapper, options, code, ...) \ - php_stream_wrapper_log_error(wrapper, options, E_WARNING, false, code, __VA_ARGS__) +#define php_stream_wrapper_log_warn_nt(wrapper, context, options, code, ...) \ + php_stream_wrapper_log_error(wrapper, context, options, E_WARNING, false, code, __VA_ARGS__) -#define php_stream_wrapper_log_notice(wrapper, options, code, ...) \ - php_stream_wrapper_log_error(wrapper, options, E_NOTICE, false, code, __VA_ARGS__) +#define php_stream_wrapper_log_notice(wrapper, context, options, code, ...) \ + php_stream_wrapper_log_error(wrapper, context, options, E_NOTICE, false, code, __VA_ARGS__) END_EXTERN_C() diff --git a/main/streams/stream_errors.c b/main/streams/stream_errors.c index 52428e9065f34..74e3af9a7a1c0 100644 --- a/main/streams/stream_errors.c +++ b/main/streams/stream_errors.c @@ -359,19 +359,15 @@ static void php_stream_wrapper_log_store_error(const php_stream_wrapper *wrapper zend_llist_add_element(list, &entry); } -static void php_stream_wrapper_log_error_internal(const php_stream_wrapper *wrapper, int options, - int severity, bool terminal, int code, const char *param, va_list args) +static void php_stream_wrapper_log_error_internal(const php_stream_wrapper *wrapper, php_stream_context *context, + int options, int severity, bool terminal, int code, const char *param, const char *fmt, va_list args) { zend_string *message = vstrpprintf(0, args, args); const char *wrapper_name = wrapper ? wrapper->wops->label : "unknown"; if (options & REPORT_ERRORS) { /* Report immediately using standard error functions */ - if (param) { - php_error_docref1(NULL, param, severity, "%s", ZSTR_VAL(message)); - } else { - php_error_docref(NULL, severity, "%s", ZSTR_VAL(message)); - } + php_stream_wrapper_error_internal(wrapper, context, options, severity, terminal, code, param, fmt, args); zend_string_release(message); } else { /* Store for later display in FG(wrapper_logged_errors) */ @@ -381,21 +377,21 @@ static void php_stream_wrapper_log_error_internal(const php_stream_wrapper *wrap } } -PHPAPI void php_stream_wrapper_log_error(const php_stream_wrapper *wrapper, int options, - int severity, bool terminal, int code, const char *fmt, ...) +PHPAPI void php_stream_wrapper_log_error(const php_stream_wrapper *wrapper, php_stream_context *context, + int options, int severity, bool terminal, int code, const char *fmt, ...) { va_list args; va_start(args, fmt); - php_stream_wrapper_log_error_internal(wrapper, options, severity, terminal, code, NULL, args); + php_stream_wrapper_log_error_internal(wrapper, context, options, severity, terminal, code, NULL, fmt, args); va_end(args); } -PHPAPI void php_stream_wrapper_log_error_param(const php_stream_wrapper *wrapper, int options, - int severity, bool terminal, int code, const char *param, const char *fmt, ...) +PHPAPI void php_stream_wrapper_log_error_param(const php_stream_wrapper *wrapper, php_stream_context *context, + int options, int severity, bool terminal, int code, const char *param, const char *fmt, ...) { va_list args; va_start(args, fmt); - php_stream_wrapper_log_error_internal(wrapper, options, severity, terminal, code, param, args); + php_stream_wrapper_log_error_internal(wrapper, context, options, severity, terminal, code, param, fmt, args); va_end(args); } From 1b00f7e99edb50539132a7fa107a5f5f82859355 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Sun, 16 Nov 2025 19:06:55 +0100 Subject: [PATCH 08/68] stream: convert php fopen wrapper --- ext/standard/php_fopen_wrapper.c | 37 +++++++--- main/streams/php_stream_errors.h | 106 ++++++++++++++------------- main/streams/stream_errors.stub.php | 10 +++ main/streams/stream_errors_arginfo.h | 4 +- 4 files changed, 94 insertions(+), 63 deletions(-) diff --git a/ext/standard/php_fopen_wrapper.c b/ext/standard/php_fopen_wrapper.c index ea33ba4904346..b13f18e08bf78 100644 --- a/ext/standard/php_fopen_wrapper.c +++ b/ext/standard/php_fopen_wrapper.c @@ -158,14 +158,18 @@ static void php_stream_apply_filter_list(php_stream *stream, char *filterlist, i if ((temp_filter = php_stream_filter_create(p, NULL, php_stream_is_persistent(stream)))) { php_stream_filter_append(&stream->readfilters, temp_filter); } else { - php_error_docref(NULL, E_WARNING, "Unable to create filter (%s)", p); + php_stream_wrapper_warn_nt(NULL, PHP_STREAM_CONTEXT(stream), REPORT_ERRORS, + STREAM_ERROR_CODE_CREATE_FAILED, + "Unable to create filter (%s)", p); } } if (write_chain) { if ((temp_filter = php_stream_filter_create(p, NULL, php_stream_is_persistent(stream)))) { php_stream_filter_append(&stream->writefilters, temp_filter); } else { - php_error_docref(NULL, E_WARNING, "Unable to create filter (%s)", p); + php_stream_wrapper_warn_nt(NULL, PHP_STREAM_CONTEXT(stream), REPORT_ERRORS, + STREAM_ERROR_CODE_CREATE_FAILED, + "Unable to create filter (%s)", p); } } p = php_strtok_r(NULL, "|", &token); @@ -219,7 +223,9 @@ static php_stream * php_stream_url_wrap_php(php_stream_wrapper *wrapper, const c if ((options & STREAM_OPEN_FOR_INCLUDE) && !PG(allow_url_include) ) { if (options & REPORT_ERRORS) { - php_error_docref(NULL, E_WARNING, "URL file-access is disabled in the server configuration"); + php_stream_wrapper_warn(wrapper, context, options, + STREAM_ERROR_CODE_DISABLED, + "URL file-access is disabled in the server configuration"); } return NULL; } @@ -238,7 +244,9 @@ static php_stream * php_stream_url_wrap_php(php_stream_wrapper *wrapper, const c if (!strcasecmp(path, "stdin")) { if ((options & STREAM_OPEN_FOR_INCLUDE) && !PG(allow_url_include) ) { if (options & REPORT_ERRORS) { - php_error_docref(NULL, E_WARNING, "URL file-access is disabled in the server configuration"); + php_stream_wrapper_warn(wrapper, context, options, + STREAM_ERROR_CODE_DISABLED, + "URL file-access is disabled in the server configuration"); } return NULL; } @@ -297,14 +305,18 @@ static php_stream * php_stream_url_wrap_php(php_stream_wrapper *wrapper, const c if (strcmp(sapi_module.name, "cli")) { if (options & REPORT_ERRORS) { - php_error_docref(NULL, E_WARNING, "Direct access to file descriptors is only available from command-line PHP"); + php_stream_wrapper_warn(wrapper, context, options, + STREAM_ERROR_CODE_DISABLED, + "Direct access to file descriptors is only available from command-line PHP"); } return NULL; } if ((options & STREAM_OPEN_FOR_INCLUDE) && !PG(allow_url_include) ) { if (options & REPORT_ERRORS) { - php_error_docref(NULL, E_WARNING, "URL file-access is disabled in the server configuration"); + php_stream_wrapper_warn(wrapper, context, options, + STREAM_ERROR_CODE_DISABLED, + "URL file-access is disabled in the server configuration"); } return NULL; } @@ -312,7 +324,8 @@ static php_stream * php_stream_url_wrap_php(php_stream_wrapper *wrapper, const c start = &path[3]; fildes_ori = ZEND_STRTOL(start, &end, 10); if (end == start || *end != '\0') { - php_stream_wrapper_log_error(wrapper, options, + php_stream_wrapper_log_warn(wrapper, context, options, + STREAM_ERROR_CODE_INVALID_URL, "php://fd/ stream must be specified in the form php://fd/"); return NULL; } @@ -324,14 +337,16 @@ static php_stream * php_stream_url_wrap_php(php_stream_wrapper *wrapper, const c #endif if (fildes_ori < 0 || fildes_ori >= dtablesize) { - php_stream_wrapper_log_error(wrapper, options, + php_stream_wrapper_log_warn(wrapper, context, options, + STREAM_ERROR_CODE_INVALID_PARAM, "The file descriptors must be non-negative numbers smaller than %d", dtablesize); return NULL; } fd = dup((int)fildes_ori); if (fd == -1) { - php_stream_wrapper_log_error(wrapper, options, + php_stream_wrapper_log_warn(wrapper, context, options, + STREAM_ERROR_CODE_DUP_FAILED, "Error duping file descriptor " ZEND_LONG_FMT "; possibly it doesn't exist: " "[%d]: %s", fildes_ori, errno, strerror(errno)); return NULL; @@ -380,7 +395,9 @@ static php_stream * php_stream_url_wrap_php(php_stream_wrapper *wrapper, const c return stream; } else { /* invalid php://thingy */ - php_error_docref(NULL, E_WARNING, "Invalid php:// URL specified"); + php_stream_wrapper_warn(wrapper, context, options, + STREAM_ERROR_CODE_INVALID_URL, + "Invalid php:// URL specified"); return NULL; } diff --git a/main/streams/php_stream_errors.h b/main/streams/php_stream_errors.h index 1ed4257bf47e8..1841ad5ceaf7a 100644 --- a/main/streams/php_stream_errors.h +++ b/main/streams/php_stream_errors.h @@ -49,67 +49,69 @@ BEGIN_EXTERN_C() #define STREAM_ERROR_CODE_NOT_WRITABLE 16 #define STREAM_ERROR_CODE_NOT_READABLE 17 /* File system operations */ -#define STREAM_ERROR_CODE_NOT_FOUND 30 -#define STREAM_ERROR_CODE_PERMISSION_DENIED 31 -#define STREAM_ERROR_CODE_ALREADY_EXISTS 32 -#define STREAM_ERROR_CODE_INVALID_PATH 33 -#define STREAM_ERROR_CODE_PATH_TOO_LONG 34 -#define STREAM_ERROR_CODE_OPEN_FAILED 35 -#define STREAM_ERROR_CODE_CREATE_FAILED 36 -#define STREAM_ERROR_CODE_UNLINK_FAILED 37 -#define STREAM_ERROR_CODE_RENAME_FAILED 38 -#define STREAM_ERROR_CODE_MKDIR_FAILED 39 -#define STREAM_ERROR_CODE_RMDIR_FAILED 40 -#define STREAM_ERROR_CODE_STAT_FAILED 41 -#define STREAM_ERROR_CODE_CHMOD_FAILED 42 -#define STREAM_ERROR_CODE_CHOWN_FAILED 43 -#define STREAM_ERROR_CODE_TOUCH_FAILED 44 -#define STREAM_ERROR_CODE_INVALID_MODE 45 -#define STREAM_ERROR_CODE_MODE_NOT_SUPPORTED 46 -#define STREAM_ERROR_CODE_READONLY 47 -#define STREAM_ERROR_CODE_RECURSION_DETECTED 48 +#define STREAM_ERROR_CODE_DISABLED 30 +#define STREAM_ERROR_CODE_NOT_FOUND 31 +#define STREAM_ERROR_CODE_PERMISSION_DENIED 32 +#define STREAM_ERROR_CODE_ALREADY_EXISTS 33 +#define STREAM_ERROR_CODE_INVALID_PATH 34 +#define STREAM_ERROR_CODE_PATH_TOO_LONG 35 +#define STREAM_ERROR_CODE_OPEN_FAILED 36 +#define STREAM_ERROR_CODE_CREATE_FAILED 37 +#define STREAM_ERROR_CODE_DUP_FAILED 38 +#define STREAM_ERROR_CODE_UNLINK_FAILED 39 +#define STREAM_ERROR_CODE_RENAME_FAILED 40 +#define STREAM_ERROR_CODE_MKDIR_FAILED 41 +#define STREAM_ERROR_CODE_RMDIR_FAILED 42 +#define STREAM_ERROR_CODE_STAT_FAILED 43 +#define STREAM_ERROR_CODE_CHMOD_FAILED 44 +#define STREAM_ERROR_CODE_CHOWN_FAILED 45 +#define STREAM_ERROR_CODE_TOUCH_FAILED 46 +#define STREAM_ERROR_CODE_INVALID_MODE 47 +#define STREAM_ERROR_CODE_MODE_NOT_SUPPORTED 48 +#define STREAM_ERROR_CODE_READONLY 49 +#define STREAM_ERROR_CODE_RECURSION_DETECTED 50 /* Wrapper/protocol operations */ -#define STREAM_ERROR_CODE_WRAPPER_NOT_FOUND 60 -#define STREAM_ERROR_CODE_WRAPPER_DISABLED 61 -#define STREAM_ERROR_CODE_PROTOCOL_UNSUPPORTED 62 -#define STREAM_ERROR_CODE_WRAPPER_REGISTRATION_FAILED 63 -#define STREAM_ERROR_CODE_WRAPPER_UNREGISTRATION_FAILED 64 -#define STREAM_ERROR_CODE_WRAPPER_RESTORATION_FAILED 65 +#define STREAM_ERROR_CODE_WRAPPER_NOT_FOUND 70 +#define STREAM_ERROR_CODE_WRAPPER_DISABLED 71 +#define STREAM_ERROR_CODE_PROTOCOL_UNSUPPORTED 72 +#define STREAM_ERROR_CODE_WRAPPER_REGISTRATION_FAILED 73 +#define STREAM_ERROR_CODE_WRAPPER_UNREGISTRATION_FAILED 74 +#define STREAM_ERROR_CODE_WRAPPER_RESTORATION_FAILED 75 /* Filter operations */ -#define STREAM_ERROR_CODE_FILTER_NOT_FOUND 80 -#define STREAM_ERROR_CODE_FILTER_FAILED 81 +#define STREAM_ERROR_CODE_FILTER_NOT_FOUND 90 +#define STREAM_ERROR_CODE_FILTER_FAILED 91 /* Cast/conversion operations */ -#define STREAM_ERROR_CODE_CAST_FAILED 90 -#define STREAM_ERROR_CODE_CAST_NOT_SUPPORTED 91 -#define STREAM_ERROR_CODE_MAKE_SEEKABLE_FAILED 92 -#define STREAM_ERROR_CODE_BUFFERED_DATA_LOST 93 +#define STREAM_ERROR_CODE_CAST_FAILED 100 +#define STREAM_ERROR_CODE_CAST_NOT_SUPPORTED 101 +#define STREAM_ERROR_CODE_MAKE_SEEKABLE_FAILED 102 +#define STREAM_ERROR_CODE_BUFFERED_DATA_LOST 103 /* Network/socket operations */ -#define STREAM_ERROR_CODE_NETWORK_SEND_FAILED 100 -#define STREAM_ERROR_CODE_NETWORK_RECV_FAILED 101 -#define STREAM_ERROR_CODE_SSL_NOT_SUPPORTED 102 -#define STREAM_ERROR_CODE_RESUMPTION_FAILED 103 -#define STREAM_ERROR_CODE_SOCKET_PATH_TOO_LONG 104 -#define STREAM_ERROR_CODE_OOB_NOT_SUPPORTED 105 -#define STREAM_ERROR_CODE_PROTOCOL_ERROR 106 -#define STREAM_ERROR_CODE_INVALID_URL 107 -#define STREAM_ERROR_CODE_INVALID_RESPONSE 108 -#define STREAM_ERROR_CODE_INVALID_HEADER 109 +#define STREAM_ERROR_CODE_NETWORK_SEND_FAILED 110 +#define STREAM_ERROR_CODE_NETWORK_RECV_FAILED 111 +#define STREAM_ERROR_CODE_SSL_NOT_SUPPORTED 112 +#define STREAM_ERROR_CODE_RESUMPTION_FAILED 113 +#define STREAM_ERROR_CODE_SOCKET_PATH_TOO_LONG 114 +#define STREAM_ERROR_CODE_OOB_NOT_SUPPORTED 115 +#define STREAM_ERROR_CODE_PROTOCOL_ERROR 116 +#define STREAM_ERROR_CODE_INVALID_URL 117 +#define STREAM_ERROR_CODE_INVALID_RESPONSE 118 +#define STREAM_ERROR_CODE_INVALID_HEADER 119 #define STREAM_ERROR_CODE_INVALID_PARAM 110 -#define STREAM_ERROR_CODE_REDIRECT_LIMIT 111 -#define STREAM_ERROR_CODE_AUTH_FAILED 112 +#define STREAM_ERROR_CODE_REDIRECT_LIMIT 121 +#define STREAM_ERROR_CODE_AUTH_FAILED 122 /* Encoding/decoding/archiving operations */ -#define STREAM_ERROR_CODE_ARCHIVING_FAILED 120 -#define STREAM_ERROR_CODE_ENCODING_FAILED 121 -#define STREAM_ERROR_CODE_INVALID_FORMAT 122 +#define STREAM_ERROR_CODE_ARCHIVING_FAILED 130 +#define STREAM_ERROR_CODE_ENCODING_FAILED 131 +#define STREAM_ERROR_CODE_INVALID_FORMAT 132 /* Resource/allocation operations */ -#define STREAM_ERROR_CODE_ALLOCATION_FAILED 130 -#define STREAM_ERROR_CODE_TEMPORARY_FILE_FAILED 131 +#define STREAM_ERROR_CODE_ALLOCATION_FAILED 140 +#define STREAM_ERROR_CODE_TEMPORARY_FILE_FAILED 141 /* Locking operations */ -#define STREAM_ERROR_CODE_LOCK_FAILED 140 -#define STREAM_ERROR_CODE_LOCK_NOT_SUPPORTED 141 +#define STREAM_ERROR_CODE_LOCK_FAILED 150 +#define STREAM_ERROR_CODE_LOCK_NOT_SUPPORTED 151 /* Userspace stream operations */ -#define STREAM_ERROR_CODE_USERSPACE_NOT_IMPLEMENTED 150 -#define STREAM_ERROR_CODE_USERSPACE_INVALID_RETURN 151 +#define STREAM_ERROR_CODE_USERSPACE_NOT_IMPLEMENTED 160 +#define STREAM_ERROR_CODE_USERSPACE_INVALID_RETURN 161 /* Stored error entry */ typedef struct { diff --git a/main/streams/stream_errors.stub.php b/main/streams/stream_errors.stub.php index 7e76865b02a62..7bec3e68db235 100644 --- a/main/streams/stream_errors.stub.php +++ b/main/streams/stream_errors.stub.php @@ -61,6 +61,11 @@ public function getWrapperName(): string {} * @cvalue STREAM_ERROR_CODE_NOT_READABLE */ const STREAM_ERROR_CODE_NOT_READABLE = UNKNOWN; +/** + * @var int + * @cvalue STREAM_ERROR_CODE_DISABLED + */ +const STREAM_ERROR_CODE_DISABLED = UNKNOWN; /** * @var int * @cvalue STREAM_ERROR_CODE_NOT_FOUND @@ -91,6 +96,11 @@ public function getWrapperName(): string {} * @cvalue STREAM_ERROR_CODE_CREATE_FAILED */ const STREAM_ERROR_CODE_CREATE_FAILED = UNKNOWN; +/** + * @var int + * @cvalue STREAM_ERROR_CODE_DUP_FAILED + */ +const STREAM_ERROR_CODE_DUP_FAILED = UNKNOWN; /** * @var int * @cvalue STREAM_ERROR_CODE_OPEN_FAILED diff --git a/main/streams/stream_errors_arginfo.h b/main/streams/stream_errors_arginfo.h index dd2051c0e10df..dca72e8b8375c 100644 --- a/main/streams/stream_errors_arginfo.h +++ b/main/streams/stream_errors_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: c40a28ed8224ab9fc3673ca4dec0d5376f9acd7e */ + * Stub hash: ea73ead3bd777bd305d626af87d75dfc21140f97 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_StreamException_getParam, 0, 0, IS_STRING, 1) ZEND_END_ARG_INFO() @@ -28,12 +28,14 @@ static void register_stream_errors_symbols(int module_number) REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_TRUNCATE_FAILED", STREAM_ERROR_CODE_TRUNCATE_FAILED, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_NOT_WRITABLE", STREAM_ERROR_CODE_NOT_WRITABLE, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_NOT_READABLE", STREAM_ERROR_CODE_NOT_READABLE, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_DISABLED", STREAM_ERROR_CODE_DISABLED, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_NOT_FOUND", STREAM_ERROR_CODE_NOT_FOUND, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_PERMISSION_DENIED", STREAM_ERROR_CODE_PERMISSION_DENIED, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_ALREADY_EXISTS", STREAM_ERROR_CODE_ALREADY_EXISTS, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_INVALID_PATH", STREAM_ERROR_CODE_INVALID_PATH, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_PATH_TOO_LONG", STREAM_ERROR_CODE_PATH_TOO_LONG, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_CREATE_FAILED", STREAM_ERROR_CODE_CREATE_FAILED, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_DUP_FAILED", STREAM_ERROR_CODE_DUP_FAILED, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_OPEN_FAILED", STREAM_ERROR_CODE_OPEN_FAILED, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_UNLINK_FAILED", STREAM_ERROR_CODE_UNLINK_FAILED, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_RENAME_FAILED", STREAM_ERROR_CODE_RENAME_FAILED, CONST_PERSISTENT); From ff51dec59e450e320bef9e5e8b88eab47b35c47e Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Sun, 16 Nov 2025 19:22:05 +0100 Subject: [PATCH 09/68] stream: convert memory wrappers errors --- main/streams/memory.c | 25 +++++++++++++++++-------- main/streams/php_stream_errors.h | 3 ++- main/streams/stream_errors.stub.php | 5 +++++ main/streams/stream_errors_arginfo.h | 3 ++- 4 files changed, 26 insertions(+), 10 deletions(-) diff --git a/main/streams/memory.c b/main/streams/memory.c index 9cb94542df6f5..1d0685f133a49 100644 --- a/main/streams/memory.c +++ b/main/streams/memory.c @@ -364,7 +364,9 @@ static ssize_t php_stream_temp_write(php_stream *stream, const char *buf, size_t zend_string *membuf = php_stream_memory_get_buffer(ts->innerstream); php_stream *file = php_stream_fopen_temporary_file(ts->tmpdir, "php", NULL); if (file == NULL) { - php_error_docref(NULL, E_WARNING, "Unable to create temporary file, Check permissions in temporary files directory."); + php_stream_wrapper_warn(NULL, PHP_STREAM_CONTEXT(stream), REPORT_ERRORS, + STREAM_ERROR_CODE_PERMISSION_DENIED, + "Unable to create temporary file, Check permissions in temporary files directory."); return 0; } php_stream_write(file, ZSTR_VAL(membuf), ZSTR_LEN(membuf)); @@ -491,7 +493,8 @@ static int php_stream_temp_cast(php_stream *stream, int castas, void **ret) file = php_stream_fopen_tmpfile(); if (file == NULL) { - php_error_docref(NULL, E_WARNING, "Unable to create temporary file."); + php_stream_wrapper_warn(NULL, PHP_STREAM_CONTEXT(stream), REPORT_ERRORS, + STREAM_ERROR_CODE_PERMISSION_DENIED, "Unable to create temporary file."); return FAILURE; } @@ -641,7 +644,8 @@ static php_stream * php_stream_url_wrap_rfc2397(php_stream_wrapper *wrapper, con } if ((comma = (char *) memchr(path, ',', dlen)) == NULL) { - php_stream_wrapper_log_error(wrapper, options, "rfc2397: no comma in URL"); + php_stream_wrapper_log_warn(wrapper, context, options, + STREAM_ERROR_CODE_INVALID_URL, "rfc2397: no comma in URL"); return NULL; } @@ -653,7 +657,8 @@ static php_stream * php_stream_url_wrap_rfc2397(php_stream_wrapper *wrapper, con sep = memchr(path, '/', mlen); if (!semi && !sep) { - php_stream_wrapper_log_error(wrapper, options, "rfc2397: illegal media type"); + php_stream_wrapper_log_warn(wrapper, context, options, + STREAM_ERROR_CODE_INVALID_URL, "rfc2397: illegal media type"); return NULL; } @@ -668,7 +673,8 @@ static php_stream * php_stream_url_wrap_rfc2397(php_stream_wrapper *wrapper, con path += plen; } else if (semi != path || mlen != sizeof(";base64")-1 || memcmp(path, ";base64", sizeof(";base64")-1)) { /* must be error since parameters are only allowed after mediatype */ zval_ptr_dtor(&meta); - php_stream_wrapper_log_error(wrapper, options, "rfc2397: illegal media type"); + php_stream_wrapper_log_warn(wrapper, context, options, + STREAM_ERROR_CODE_INVALID_URL, "rfc2397: illegal media type"); return NULL; } /* get parameters and potentially ';base64' */ @@ -681,7 +687,8 @@ static php_stream * php_stream_url_wrap_rfc2397(php_stream_wrapper *wrapper, con if (mlen != sizeof("base64")-1 || memcmp(path, "base64", sizeof("base64")-1)) { /* must be error since parameters are only allowed after mediatype and we have no '=' sign */ zval_ptr_dtor(&meta); - php_stream_wrapper_log_error(wrapper, options, "rfc2397: illegal parameter"); + php_stream_wrapper_log_warn(wrapper, context, options, + STREAM_ERROR_CODE_INVALID_PARAM, "rfc2397: illegal parameter"); return NULL; } base64 = 1; @@ -701,7 +708,8 @@ static php_stream * php_stream_url_wrap_rfc2397(php_stream_wrapper *wrapper, con } if (mlen) { zval_ptr_dtor(&meta); - php_stream_wrapper_log_error(wrapper, options, "rfc2397: illegal URL"); + php_stream_wrapper_log_warn(wrapper, context, options, + STREAM_ERROR_CODE_INVALID_URL, "rfc2397: illegal URL"); return NULL; } } else { @@ -717,7 +725,8 @@ static php_stream * php_stream_url_wrap_rfc2397(php_stream_wrapper *wrapper, con base64_comma = php_base64_decode_ex((const unsigned char *)comma, dlen, 1); if (!base64_comma) { zval_ptr_dtor(&meta); - php_stream_wrapper_log_error(wrapper, options, "rfc2397: unable to decode"); + php_stream_wrapper_log_warn(wrapper, context, options, + STREAM_ERROR_CODE_DECODING_FAILED, "rfc2397: unable to decode"); return NULL; } comma = ZSTR_VAL(base64_comma); diff --git a/main/streams/php_stream_errors.h b/main/streams/php_stream_errors.h index 1841ad5ceaf7a..c88f4b5113002 100644 --- a/main/streams/php_stream_errors.h +++ b/main/streams/php_stream_errors.h @@ -102,7 +102,8 @@ BEGIN_EXTERN_C() /* Encoding/decoding/archiving operations */ #define STREAM_ERROR_CODE_ARCHIVING_FAILED 130 #define STREAM_ERROR_CODE_ENCODING_FAILED 131 -#define STREAM_ERROR_CODE_INVALID_FORMAT 132 +#define STREAM_ERROR_CODE_DECODING_FAILED 132 +#define STREAM_ERROR_CODE_INVALID_FORMAT 133 /* Resource/allocation operations */ #define STREAM_ERROR_CODE_ALLOCATION_FAILED 140 #define STREAM_ERROR_CODE_TEMPORARY_FILE_FAILED 141 diff --git a/main/streams/stream_errors.stub.php b/main/streams/stream_errors.stub.php index 7bec3e68db235..c55a4abfefa56 100644 --- a/main/streams/stream_errors.stub.php +++ b/main/streams/stream_errors.stub.php @@ -301,6 +301,11 @@ public function getWrapperName(): string {} * @cvalue STREAM_ERROR_CODE_ENCODING_FAILED */ const STREAM_ERROR_CODE_ENCODING_FAILED = UNKNOWN; +/** + * @var int + * @cvalue STREAM_ERROR_CODE_DECODING_FAILED + */ +const STREAM_ERROR_CODE_DECODING_FAILED = UNKNOWN; /** * @var int * @cvalue STREAM_ERROR_CODE_INVALID_FORMAT diff --git a/main/streams/stream_errors_arginfo.h b/main/streams/stream_errors_arginfo.h index dca72e8b8375c..c51b1080c998a 100644 --- a/main/streams/stream_errors_arginfo.h +++ b/main/streams/stream_errors_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: ea73ead3bd777bd305d626af87d75dfc21140f97 */ + * Stub hash: e19e8ac3e877b2f3a8a2b2ec0033c57c356daffa */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_StreamException_getParam, 0, 0, IS_STRING, 1) ZEND_END_ARG_INFO() @@ -76,6 +76,7 @@ static void register_stream_errors_symbols(int module_number) REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_AUTH_FAILED", STREAM_ERROR_CODE_AUTH_FAILED, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_ARCHIVING_FAILED", STREAM_ERROR_CODE_ARCHIVING_FAILED, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_ENCODING_FAILED", STREAM_ERROR_CODE_ENCODING_FAILED, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_DECODING_FAILED", STREAM_ERROR_CODE_DECODING_FAILED, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_INVALID_FORMAT", STREAM_ERROR_CODE_INVALID_FORMAT, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_ALLOCATION_FAILED", STREAM_ERROR_CODE_ALLOCATION_FAILED, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_TEMPORARY_FILE_FAILED", STREAM_ERROR_CODE_TEMPORARY_FILE_FAILED, CONST_PERSISTENT); From 13b256f1892c1017bcdfff8e3083d3028de67181 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Sun, 16 Nov 2025 22:10:26 +0100 Subject: [PATCH 10/68] stream: convert plain wrappers errors --- main/streams/php_stream_errors.h | 25 +++++--- main/streams/plain_wrapper.c | 93 +++++++++++++++++++--------- main/streams/stream_errors.stub.php | 10 +++ main/streams/stream_errors_arginfo.h | 4 +- 4 files changed, 94 insertions(+), 38 deletions(-) diff --git a/main/streams/php_stream_errors.h b/main/streams/php_stream_errors.h index c88f4b5113002..7f57a684b8250 100644 --- a/main/streams/php_stream_errors.h +++ b/main/streams/php_stream_errors.h @@ -63,13 +63,15 @@ BEGIN_EXTERN_C() #define STREAM_ERROR_CODE_MKDIR_FAILED 41 #define STREAM_ERROR_CODE_RMDIR_FAILED 42 #define STREAM_ERROR_CODE_STAT_FAILED 43 -#define STREAM_ERROR_CODE_CHMOD_FAILED 44 -#define STREAM_ERROR_CODE_CHOWN_FAILED 45 -#define STREAM_ERROR_CODE_TOUCH_FAILED 46 -#define STREAM_ERROR_CODE_INVALID_MODE 47 -#define STREAM_ERROR_CODE_MODE_NOT_SUPPORTED 48 -#define STREAM_ERROR_CODE_READONLY 49 -#define STREAM_ERROR_CODE_RECURSION_DETECTED 50 +#define STREAM_ERROR_CODE_META_FAILED 44 +#define STREAM_ERROR_CODE_CHMOD_FAILED 45 +#define STREAM_ERROR_CODE_CHOWN_FAILED 46 +#define STREAM_ERROR_CODE_COPY_FAILED 47 +#define STREAM_ERROR_CODE_TOUCH_FAILED 48 +#define STREAM_ERROR_CODE_INVALID_MODE 49 +#define STREAM_ERROR_CODE_MODE_NOT_SUPPORTED 50 +#define STREAM_ERROR_CODE_READONLY 51 +#define STREAM_ERROR_CODE_RECURSION_DETECTED 52 /* Wrapper/protocol operations */ #define STREAM_ERROR_CODE_WRAPPER_NOT_FOUND 70 #define STREAM_ERROR_CODE_WRAPPER_DISABLED 71 @@ -218,6 +220,15 @@ void php_stream_tidy_wrapper_error_log(php_stream_wrapper *wrapper); #define php_stream_wrapper_warn_param(wrapper, context, options, code, param, ...) \ php_stream_wrapper_error_param(wrapper, context, options, E_WARNING, true, code, param, __VA_ARGS__) +#define php_stream_wrapper_warn_param_nt(wrapper, context, options, code, param, ...) \ + php_stream_wrapper_error_param(wrapper, context, options, E_WARNING, false, code, param, __VA_ARGS__) + +#define php_stream_wrapper_warn_param2(wrapper, context, options, code, param1, param2, ...) \ + php_stream_wrapper_error_param2(wrapper, context, options, E_WARNING, true, code, param1, param2, __VA_ARGS__) + +#define php_stream_wrapper_warn_param2_nt(wrapper, context, options, code, param1, param2, ...) \ + php_stream_wrapper_error_param2(wrapper, context, options, E_WARNING, false, code, param1, param2, __VA_ARGS__) + #define php_stream_warn(stream, code, ...) \ php_stream_error(stream, E_WARNING, true, code, __VA_ARGS__) diff --git a/main/streams/plain_wrapper.c b/main/streams/plain_wrapper.c index 74d8877a7f381..d71e706f847e7 100644 --- a/main/streams/plain_wrapper.c +++ b/main/streams/plain_wrapper.c @@ -394,7 +394,8 @@ static ssize_t php_stdiop_write(php_stream *stream, const char *buf, size_t coun } if (!(stream->flags & PHP_STREAM_FLAG_SUPPRESS_ERRORS)) { char errstr[256]; - php_error_docref(NULL, E_NOTICE, "Write of %zu bytes failed with errno=%d %s", + php_stream_notice(stream, STREAM_ERROR_CODE_WRITE_FAILED, + "Write of %zu bytes failed with errno=%d %s", count, errno, php_socket_strerror_s(errno, errstr, sizeof(errstr))); } } @@ -472,7 +473,8 @@ static ssize_t php_stdiop_read(php_stream *stream, char *buf, size_t count) } else { if (!(stream->flags & PHP_STREAM_FLAG_SUPPRESS_ERRORS)) { char errstr[256]; - php_error_docref(NULL, E_NOTICE, "Read of %zu bytes failed with errno=%d %s", + php_stream_notice(stream, STREAM_ERROR_CODE_READ_FAILED, + "Read of %zu bytes failed with errno=%d %s", count, errno, php_socket_strerror_s(errno, errstr, sizeof(errstr))); } @@ -621,7 +623,8 @@ static int php_stdiop_seek(php_stream *stream, zend_off_t offset, int whence, ze assert(data != NULL); if (!data->is_seekable) { - php_error_docref(NULL, E_WARNING, "Cannot seek on this stream"); + php_stream_wrapper_warn(NULL, PHP_STREAM_CONTEXT(stream), REPORT_ERRORS, + STREAM_ERROR_CODE_SEEK_NOT_SUPPORTED, "Cannot seek on this stream"); return -1; } @@ -1158,7 +1161,8 @@ PHPAPI php_stream *_php_stream_fopen(const char *filename, const char *mode, zen char *persistent_id = NULL; if (FAILURE == php_stream_parse_fopen_modes(mode, &open_flags)) { - php_stream_wrapper_log_error(&php_plain_files_wrapper, options, "`%s' is not a valid mode for fopen", mode); + php_stream_wrapper_log_warn(&php_plain_files_wrapper, NULL, options, + STREAM_ERROR_CODE_INVALID_MODE, "`%s' is not a valid mode for fopen", mode); return NULL; } @@ -1311,8 +1315,9 @@ static int php_plain_files_unlink(php_stream_wrapper *wrapper, const char *url, if (ret == -1) { if (options & REPORT_ERRORS) { char errstr[256]; - php_error_docref1(NULL, url, E_WARNING, "%s", - php_socket_strerror_s(errno, errstr, sizeof(errstr))); + php_stream_wrapper_warn_param(wrapper, context, options, + STREAM_ERROR_CODE_UNLINK_FAILED, url, + "%s", php_socket_strerror_s(errno, errstr, sizeof(errstr))); } return 0; } @@ -1379,20 +1384,22 @@ static int php_plain_files_rename(php_stream_wrapper *wrapper, const char *url_f * access to the file in the meantime. */ if (VCWD_CHOWN(url_to, sb.st_uid, sb.st_gid)) { - php_error_docref2(NULL, url_from, url_to, E_WARNING, "%s", - php_socket_strerror_s(errno, errstr, sizeof(errstr))); if (errno != EPERM) { success = 0; } + php_stream_wrapper_error_param2(wrapper, context, options, E_WARNING, + !success, STREAM_ERROR_CODE_CHOWN_FAILED, url_from, url_to, + "%s", php_socket_strerror_s(errno, errstr, sizeof(errstr))); } if (success) { if (VCWD_CHMOD(url_to, sb.st_mode)) { - php_error_docref2(NULL, url_from, url_to, E_WARNING, "%s", - php_socket_strerror_s(errno, errstr, sizeof(errstr))); if (errno != EPERM) { success = 0; } + php_stream_wrapper_error_param2(wrapper, context, options, E_WARNING, + !success, STREAM_ERROR_CODE_CHOWN_FAILED, url_from, url_to, + "%s", php_socket_strerror_s(errno, errstr, sizeof(errstr))); } } # endif @@ -1400,12 +1407,14 @@ static int php_plain_files_rename(php_stream_wrapper *wrapper, const char *url_f VCWD_UNLINK(url_from); } } else { - php_error_docref2(NULL, url_from, url_to, E_WARNING, "%s", - php_socket_strerror_s(errno, errstr, sizeof(errstr))); + php_stream_wrapper_warn_param2_nt(wrapper, context, options, + STREAM_ERROR_CODE_STAT_FAILED, url_from, url_to, + "%s", php_socket_strerror_s(errno, errstr, sizeof(errstr))); } } else { - php_error_docref2(NULL, url_from, url_to, E_WARNING, "%s", - php_socket_strerror_s(errno, errstr, sizeof(errstr))); + php_stream_wrapper_warn_param2_nt(wrapper, context, options, + STREAM_ERROR_CODE_COPY_FAILED, url_from, url_to, + "%s", php_socket_strerror_s(errno, errstr, sizeof(errstr))); } # if !defined(ZTS) && !defined(TSRM_WIN32) umask(oldmask); @@ -1418,8 +1427,9 @@ static int php_plain_files_rename(php_stream_wrapper *wrapper, const char *url_f #ifdef PHP_WIN32 php_win32_docref2_from_error(GetLastError(), url_from, url_to); #else - php_error_docref2(NULL, url_from, url_to, E_WARNING, "%s", - php_socket_strerror_s(errno, errstr, sizeof(errstr))); + php_stream_wrapper_warn_param2(wrapper, context, options, + STREAM_ERROR_CODE_RENAME_FAILED, url_from, url_to, + "%s", php_socket_strerror_s(errno, errstr, sizeof(errstr))); #endif return 0; } @@ -1443,7 +1453,8 @@ static int php_plain_files_mkdir(php_stream_wrapper *wrapper, const char *dir, i int ret = VCWD_MKDIR(dir, (mode_t)mode); if (ret < 0 && (options & REPORT_ERRORS)) { - php_error_docref(NULL, E_WARNING, "%s", strerror(errno)); + php_stream_wrapper_warn(wrapper, context, options, + STREAM_ERROR_CODE_MKDIR_FAILED, "%s", strerror(errno)); return 0; } @@ -1452,7 +1463,8 @@ static int php_plain_files_mkdir(php_stream_wrapper *wrapper, const char *dir, i char buf[MAXPATHLEN]; if (!expand_filepath_with_mode(dir, buf, NULL, 0, CWD_EXPAND)) { - php_error_docref(NULL, E_WARNING, "Invalid path"); + php_stream_wrapper_warn(wrapper, context, options, + STREAM_ERROR_CODE_INVALID_PATH, "Invalid path"); return 0; } @@ -1504,7 +1516,9 @@ static int php_plain_files_mkdir(php_stream_wrapper *wrapper, const char *dir, i int ret = VCWD_MKDIR(buf, (mode_t) mode); if (ret < 0 && errno != EEXIST) { if (options & REPORT_ERRORS) { - php_error_docref(NULL, E_WARNING, "%s", php_socket_strerror_s(errno, errstr, sizeof(errstr))); + php_stream_wrapper_warn(wrapper, context, options, + STREAM_ERROR_CODE_MKDIR_FAILED, + "%s", php_socket_strerror_s(errno, errstr, sizeof(errstr))); } return 0; } @@ -1524,7 +1538,9 @@ static int php_plain_files_mkdir(php_stream_wrapper *wrapper, const char *dir, i /* issue a warning to client when the last directory was created failed */ if (ret < 0) { if (options & REPORT_ERRORS) { - php_error_docref(NULL, E_WARNING, "%s", php_socket_strerror_s(errno, errstr, sizeof(errstr))); + php_stream_wrapper_warn(wrapper, context, options, + STREAM_ERROR_CODE_MKDIR_FAILED, + "%s", php_socket_strerror_s(errno, errstr, sizeof(errstr))); } return 0; } @@ -1546,13 +1562,17 @@ static int php_plain_files_rmdir(php_stream_wrapper *wrapper, const char *url, i char errstr[256]; #ifdef PHP_WIN32 if (!php_win32_check_trailing_space(url, strlen(url))) { - php_error_docref1(NULL, url, E_WARNING, "%s", php_socket_strerror_s(ENOENT, errstr, sizeof(errstr))); + php_stream_wrapper_warn_param(wrapper, context, options, + STREAM_ERROR_CODE_NOT_FOUND, url, + "%s", php_socket_strerror_s(ENOENT, errstr, sizeof(errstr))); return 0; } #endif if (VCWD_RMDIR(url) < 0) { - php_error_docref1(NULL, url, E_WARNING, "%s", php_socket_strerror_s(errno, errstr, sizeof(errstr))); + php_stream_wrapper_warn_param(wrapper, context, options, + STREAM_ERROR_CODE_RMDIR_FAILED, url, + "%s", php_socket_strerror_s(errno, errstr, sizeof(errstr))); return 0; } @@ -1575,7 +1595,9 @@ static int php_plain_files_metadata(php_stream_wrapper *wrapper, const char *url #ifdef PHP_WIN32 if (!php_win32_check_trailing_space(url, strlen(url))) { - php_error_docref1(NULL, url, E_WARNING, "%s", php_socket_strerror_s(ENOENT, errstr, sizeof(errstr))); + php_stream_wrapper_warn_param(wrapper, context, REPORT_ERRORS, + STREAM_ERROR_CODE_NOT_FOUND, url, + "%s", php_socket_strerror_s(ENOENT, errstr, sizeof(errstr))); return 0; } #endif @@ -1594,7 +1616,9 @@ static int php_plain_files_metadata(php_stream_wrapper *wrapper, const char *url if (VCWD_ACCESS(url, F_OK) != 0) { FILE *file = VCWD_FOPEN(url, "w"); if (file == NULL) { - php_error_docref1(NULL, url, E_WARNING, "Unable to create file %s because %s", url, + php_stream_wrapper_warn_param(wrapper, context, REPORT_ERRORS, + STREAM_ERROR_CODE_PERMISSION_DENIED, url, + "Unable to create file %s because %s", url, php_socket_strerror_s(errno, errstr, sizeof(errstr))); return 0; } @@ -1608,7 +1632,9 @@ static int php_plain_files_metadata(php_stream_wrapper *wrapper, const char *url case PHP_STREAM_META_OWNER: if(option == PHP_STREAM_META_OWNER_NAME) { if(php_get_uid_by_name((char *)value, &uid) != SUCCESS) { - php_error_docref1(NULL, url, E_WARNING, "Unable to find uid for %s", (char *)value); + php_stream_wrapper_warn_param(wrapper, context, REPORT_ERRORS, + STREAM_ERROR_CODE_META_FAILED, url, + "Unable to find uid for %s", (char *)value); return 0; } } else { @@ -1620,7 +1646,9 @@ static int php_plain_files_metadata(php_stream_wrapper *wrapper, const char *url case PHP_STREAM_META_GROUP_NAME: if(option == PHP_STREAM_META_GROUP_NAME) { if(php_get_gid_by_name((char *)value, &gid) != SUCCESS) { - php_error_docref1(NULL, url, E_WARNING, "Unable to find gid for %s", (char *)value); + php_stream_wrapper_warn_param(wrapper, context, REPORT_ERRORS, + STREAM_ERROR_CODE_META_FAILED, url, + "Unable to find gid for %s", (char *)value); return 0; } } else { @@ -1638,8 +1666,9 @@ static int php_plain_files_metadata(php_stream_wrapper *wrapper, const char *url return 0; } if (ret == -1) { - php_error_docref1(NULL, url, E_WARNING, "Operation failed: %s", - php_socket_strerror_s(errno, errstr, sizeof(errstr))); + php_stream_wrapper_warn_param(wrapper, context, REPORT_ERRORS, + STREAM_ERROR_CODE_META_FAILED, url, + "Operation failed: %s", php_socket_strerror_s(errno, errstr, sizeof(errstr))); return 0; } php_clear_stat_cache(0, NULL, 0); @@ -1732,7 +1761,9 @@ PHPAPI php_stream *_php_stream_fopen_with_path(const char *filename, const char *(cwd+3) = '\0'; if (snprintf(trypath, MAXPATHLEN, "%s%s", cwd, filename) >= MAXPATHLEN) { - php_error_docref(NULL, E_NOTICE, "%s/%s path was truncated to %d", cwd, filename, MAXPATHLEN); + php_stream_wrapper_notice(NULL, NULL, REPORT_ERRORS, + STREAM_ERROR_CODE_PATH_TOO_LONG, + "%s/%s path was truncated to %d", cwd, filename, MAXPATHLEN); } efree(cwd); @@ -1787,7 +1818,9 @@ PHPAPI php_stream *_php_stream_fopen_with_path(const char *filename, const char goto stream_skip; } if (snprintf(trypath, MAXPATHLEN, "%s/%s", ptr, filename) >= MAXPATHLEN) { - php_error_docref(NULL, E_NOTICE, "%s/%s path was truncated to %d", ptr, filename, MAXPATHLEN); + php_stream_wrapper_notice(NULL, NULL, REPORT_ERRORS, + STREAM_ERROR_CODE_PATH_TOO_LONG, + "%s/%s path was truncated to %d", ptr, filename, MAXPATHLEN); } if (((options & STREAM_DISABLE_OPEN_BASEDIR) == 0) && php_check_open_basedir_ex(trypath, 0)) { diff --git a/main/streams/stream_errors.stub.php b/main/streams/stream_errors.stub.php index c55a4abfefa56..b600a7faa796d 100644 --- a/main/streams/stream_errors.stub.php +++ b/main/streams/stream_errors.stub.php @@ -131,6 +131,11 @@ public function getWrapperName(): string {} * @cvalue STREAM_ERROR_CODE_STAT_FAILED */ const STREAM_ERROR_CODE_STAT_FAILED = UNKNOWN; +/** + * @var int + * @cvalue STREAM_ERROR_CODE_META_FAILED + */ +const STREAM_ERROR_CODE_META_FAILED = UNKNOWN; /** * @var int * @cvalue STREAM_ERROR_CODE_CHMOD_FAILED @@ -141,6 +146,11 @@ public function getWrapperName(): string {} * @cvalue STREAM_ERROR_CODE_CHOWN_FAILED */ const STREAM_ERROR_CODE_CHOWN_FAILED = UNKNOWN; +/** + * @var int + * @cvalue STREAM_ERROR_CODE_COPY_FAILED + */ +const STREAM_ERROR_CODE_COPY_FAILED = UNKNOWN; /** * @var int * @cvalue STREAM_ERROR_CODE_TOUCH_FAILED diff --git a/main/streams/stream_errors_arginfo.h b/main/streams/stream_errors_arginfo.h index c51b1080c998a..5859f825c4ee4 100644 --- a/main/streams/stream_errors_arginfo.h +++ b/main/streams/stream_errors_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: e19e8ac3e877b2f3a8a2b2ec0033c57c356daffa */ + * Stub hash: c14298e97a4960fe35b7b1b464a5b0b94099897f */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_StreamException_getParam, 0, 0, IS_STRING, 1) ZEND_END_ARG_INFO() @@ -42,8 +42,10 @@ static void register_stream_errors_symbols(int module_number) REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_MKDIR_FAILED", STREAM_ERROR_CODE_MKDIR_FAILED, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_RMDIR_FAILED", STREAM_ERROR_CODE_RMDIR_FAILED, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_STAT_FAILED", STREAM_ERROR_CODE_STAT_FAILED, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_META_FAILED", STREAM_ERROR_CODE_META_FAILED, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_CHMOD_FAILED", STREAM_ERROR_CODE_CHMOD_FAILED, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_CHOWN_FAILED", STREAM_ERROR_CODE_CHOWN_FAILED, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_COPY_FAILED", STREAM_ERROR_CODE_COPY_FAILED, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_TOUCH_FAILED", STREAM_ERROR_CODE_TOUCH_FAILED, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_INVALID_MODE", STREAM_ERROR_CODE_INVALID_MODE, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_MODE_NOT_SUPPORTED", STREAM_ERROR_CODE_MODE_NOT_SUPPORTED, CONST_PERSISTENT); From 0e3c995f5e95c22cf45731f115f92d9cc00e8c9f Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Sun, 16 Nov 2025 22:17:32 +0100 Subject: [PATCH 11/68] stream: convert cast errors --- main/streams/cast.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/main/streams/cast.c b/main/streams/cast.c index 4dc8ddb5f6a30..3322c9d50f184 100644 --- a/main/streams/cast.c +++ b/main/streams/cast.c @@ -189,7 +189,6 @@ void php_stream_mode_sanitize_fdopen_fopencookie(php_stream *stream, char *resul result[res_curs] = '\0'; } /* }}} */ - /* {{{ php_stream_cast */ PHPAPI zend_result _php_stream_cast(php_stream *stream, int castas, void **ret, int show_err) { @@ -259,7 +258,7 @@ PHPAPI zend_result _php_stream_cast(php_stream *stream, int castas, void **ret, b) no memory -> lets bail */ - php_error_docref(NULL, E_ERROR, "fopencookie failed"); + php_stream_fatal(stream, STREAM_ERROR_CODE_CAST_FAILED, "fopencookie failed"); return FAILURE; #endif @@ -299,7 +298,8 @@ PHPAPI zend_result _php_stream_cast(php_stream *stream, int castas, void **ret, if (php_stream_is_filtered(stream) && castas != PHP_STREAM_AS_FD_FOR_SELECT) { if (show_err) { - php_error_docref(NULL, E_WARNING, "Cannot cast a filtered stream on this system"); + php_stream_warn(stream, STREAM_ERROR_CODE_CAST_NOT_SUPPORTED, + "Cannot cast a filtered stream on this system"); } return FAILURE; } else if (stream->ops->cast && stream->ops->cast(stream, castas, ret) == SUCCESS) { @@ -315,7 +315,8 @@ PHPAPI zend_result _php_stream_cast(php_stream *stream, int castas, void **ret, "select()able descriptor" }; - php_error_docref(NULL, E_WARNING, "Cannot represent a stream of type %s as a %s", stream->ops->label, cast_names[castas]); + php_stream_warn(stream, STREAM_ERROR_CODE_CAST_NOT_SUPPORTED, + "Cannot represent a stream of type %s as a %s", stream->ops->label, cast_names[castas]); } return FAILURE; @@ -330,7 +331,9 @@ PHPAPI zend_result _php_stream_cast(php_stream *stream, int castas, void **ret, * will be accessing the stream. Emit a warning so that the end-user will * know that they should try something else */ - php_error_docref(NULL, E_WARNING, ZEND_LONG_FMT " bytes of buffered data lost during stream conversion!", (zend_long)(stream->writepos - stream->readpos)); + php_stream_warn_nt(stream, STREAM_ERROR_CODE_BUFFERED_DATA_LOST, + ZEND_LONG_FMT " bytes of buffered data lost during stream conversion!", + (zend_long)(stream->writepos - stream->readpos)); } if (castas == PHP_STREAM_AS_STDIO && ret) { From 703e8c87076fba028caa8e5313d0681781517db2 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Sun, 16 Nov 2025 22:23:41 +0100 Subject: [PATCH 12/68] stream: convert filter errors --- main/streams/filter.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/main/streams/filter.c b/main/streams/filter.c index d0c1fdc8e788c..5c98e2c2faae3 100644 --- a/main/streams/filter.c +++ b/main/streams/filter.c @@ -343,7 +343,8 @@ PHPAPI zend_result php_stream_filter_append_ex(php_stream_filter_chain *chain, p php_stream_bucket_unlink(bucket); php_stream_bucket_delref(bucket); } - php_error_docref(NULL, E_WARNING, "Filter failed to process pre-buffered data"); + php_stream_warn(stream, STREAM_ERROR_CODE_FILTER_FAILED, + "Filter failed to process pre-buffered data"); return FAILURE; case PSFS_FEED_ME: /* We don't actually need data yet, From dc8d38b9a6cd94fddafd2b385e94a2ede802e8c4 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Sun, 16 Nov 2025 22:52:22 +0100 Subject: [PATCH 13/68] stream: convert core streams errors --- main/streams/php_stream_errors.h | 14 +++++++----- main/streams/stream_errors.stub.php | 10 +++++++++ main/streams/streams.c | 35 ++++++++++++++++++++--------- 3 files changed, 43 insertions(+), 16 deletions(-) diff --git a/main/streams/php_stream_errors.h b/main/streams/php_stream_errors.h index 7f57a684b8250..34894d2512706 100644 --- a/main/streams/php_stream_errors.h +++ b/main/streams/php_stream_errors.h @@ -73,12 +73,14 @@ BEGIN_EXTERN_C() #define STREAM_ERROR_CODE_READONLY 51 #define STREAM_ERROR_CODE_RECURSION_DETECTED 52 /* Wrapper/protocol operations */ -#define STREAM_ERROR_CODE_WRAPPER_NOT_FOUND 70 -#define STREAM_ERROR_CODE_WRAPPER_DISABLED 71 -#define STREAM_ERROR_CODE_PROTOCOL_UNSUPPORTED 72 -#define STREAM_ERROR_CODE_WRAPPER_REGISTRATION_FAILED 73 -#define STREAM_ERROR_CODE_WRAPPER_UNREGISTRATION_FAILED 74 -#define STREAM_ERROR_CODE_WRAPPER_RESTORATION_FAILED 75 +#define STREAM_ERROR_CODE_NO_OPENER 70 +#define STREAM_ERROR_CODE_PERSISTENT_NOT_SUPPORTED 71 +#define STREAM_ERROR_CODE_WRAPPER_NOT_FOUND 72 +#define STREAM_ERROR_CODE_WRAPPER_DISABLED 73 +#define STREAM_ERROR_CODE_PROTOCOL_UNSUPPORTED 74 +#define STREAM_ERROR_CODE_WRAPPER_REGISTRATION_FAILED 75 +#define STREAM_ERROR_CODE_WRAPPER_UNREGISTRATION_FAILED 76 +#define STREAM_ERROR_CODE_WRAPPER_RESTORATION_FAILED 77 /* Filter operations */ #define STREAM_ERROR_CODE_FILTER_NOT_FOUND 90 #define STREAM_ERROR_CODE_FILTER_FAILED 91 diff --git a/main/streams/stream_errors.stub.php b/main/streams/stream_errors.stub.php index b600a7faa796d..802a90e00fb8d 100644 --- a/main/streams/stream_errors.stub.php +++ b/main/streams/stream_errors.stub.php @@ -176,6 +176,16 @@ public function getWrapperName(): string {} * @cvalue STREAM_ERROR_CODE_RECURSION_DETECTED */ const STREAM_ERROR_CODE_RECURSION_DETECTED = UNKNOWN; +/** + * @var int + * @cvalue STREAM_ERROR_CODE_NO_OPENER + */ +const STREAM_ERROR_CODE_NO_OPENER = UNKNOWN; +/** + * @var int + * @cvalue STREAM_ERROR_CODE_PERSISTENT_NOT_SUPPORTED + */ +const STREAM_ERROR_CODE_PERSISTENT_NOT_SUPPORTED = UNKNOWN; /** * @var int * @cvalue STREAM_ERROR_CODE_WRAPPER_NOT_FOUND diff --git a/main/streams/streams.c b/main/streams/streams.c index 40f0fe7d49fed..c38af809d1a6a 100644 --- a/main/streams/streams.c +++ b/main/streams/streams.c @@ -1185,7 +1185,7 @@ PHPAPI ssize_t _php_stream_write(php_stream *stream, const char *buf, size_t cou ZEND_ASSERT(buf != NULL); if (stream->ops->write == NULL) { - php_error_docref(NULL, E_NOTICE, "Stream is not writable"); + php_stream_notice(stream, STREAM_ERROR_CODE_NOT_WRITABLE, "Stream is not writable"); return (ssize_t) -1; } @@ -1319,7 +1319,8 @@ PHPAPI int _php_stream_seek(php_stream *stream, zend_off_t offset, int whence) return 0; } - php_error_docref(NULL, E_WARNING, "Stream does not support seeking"); + php_stream_warn(stream, STREAM_ERROR_CODE_SEEK_NOT_SUPPORTED, + "Stream does not support seeking"); return -1; } @@ -1920,7 +1921,9 @@ PHPAPI php_stream_wrapper *php_stream_locate_url_wrapper(const char *path, const if (!localhost && path[n+3] != '\0' && path[n+3] != '/') { #endif if (options & REPORT_ERRORS) { - php_error_docref(NULL, E_WARNING, "Remote host file access not supported, %s", path); + php_stream_wrapper_warn(plain_files_wrapper, NULL, options, + STREAM_ERROR_CODE_PROTOCOL_UNSUPPORTED, + "Remote host file access not supported, %s", path); } return NULL; } @@ -1959,7 +1962,9 @@ PHPAPI php_stream_wrapper *php_stream_locate_url_wrapper(const char *path, const } if (options & REPORT_ERRORS) { - php_error_docref(NULL, E_WARNING, "file:// wrapper is disabled in the server configuration"); + php_stream_wrapper_warn(plain_files_wrapper, NULL, options, + STREAM_ERROR_CODE_DISABLED, + "file:// wrapper is disabled in the server configuration"); } return NULL; } @@ -2057,7 +2062,8 @@ PHPAPI php_stream *_php_stream_opendir(const char *path, int options, stream->flags |= PHP_STREAM_FLAG_NO_BUFFER | PHP_STREAM_FLAG_IS_DIR; } } else if (wrapper) { - php_stream_wrapper_log_error(wrapper, options & ~REPORT_ERRORS, "not implemented"); + php_stream_wrapper_log_warn(wrapper, context, options & ~REPORT_ERRORS, + STREAM_ERROR_CODE_NO_OPENER, "not implemented"); } if (stream == NULL && (options & REPORT_ERRORS)) { php_stream_display_wrapper_errors(wrapper, path, "Failed to open directory"); @@ -2127,7 +2133,13 @@ PHPAPI php_stream *_php_stream_open_wrapper_ex(const char *path, const char *mod wrapper = php_stream_locate_url_wrapper(path, &path_to_open, options); if ((options & STREAM_USE_URL) && (!wrapper || !wrapper->is_url)) { - php_error_docref(NULL, E_WARNING, "This function may only be used against URLs"); + if (wrapper) { + php_stream_wrapper_warn(wrapper, context, options, + STREAM_ERROR_CODE_PROTOCOL_UNSUPPORTED, + "This function may only be used against URLs"); + } else { + php_error_docref(NULL, E_WARNING, "This function may only be used against URLs"); + } if (resolved_path) { zend_string_release_ex(resolved_path, 0); } @@ -2136,7 +2148,8 @@ PHPAPI php_stream *_php_stream_open_wrapper_ex(const char *path, const char *mod if (wrapper) { if (!wrapper->wops->stream_opener) { - php_stream_wrapper_log_error(wrapper, options & ~REPORT_ERRORS, + php_stream_wrapper_log_warn(wrapper, context, options & ~REPORT_ERRORS, + STREAM_ERROR_CODE_NO_OPENER, "wrapper does not support stream open"); } else { stream = wrapper->wops->stream_opener(wrapper, @@ -2147,7 +2160,8 @@ PHPAPI php_stream *_php_stream_open_wrapper_ex(const char *path, const char *mod /* if the caller asked for a persistent stream but the wrapper did not * return one, force an error here */ if (stream && persistent && !stream->is_persistent) { - php_stream_wrapper_log_error(wrapper, options & ~REPORT_ERRORS, + php_stream_wrapper_log_warn(wrapper, context, options & ~REPORT_ERRORS, + STREAM_ERROR_CODE_PERSISTENT_NOT_SUPPORTED, "wrapper does not support persistent streams"); php_stream_close(stream); stream = NULL; @@ -2199,8 +2213,9 @@ PHPAPI php_stream *_php_stream_open_wrapper_ex(const char *path, const char *mod if (options & REPORT_ERRORS) { char *tmp = estrdup(path); php_strip_url_passwd(tmp); - php_error_docref1(NULL, tmp, E_WARNING, "could not make seekable - %s", - tmp); + php_stream_wrapper_warn_param(wrapper, context, options, + STREAM_ERROR_CODE_SEEK_NOT_SUPPORTED, tmp, + "could not make seekable - %s", tmp); efree(tmp); options &= ~REPORT_ERRORS; From c906551d50840d86d686f559446a2c20ccb035a7 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Mon, 17 Nov 2025 12:50:58 +0100 Subject: [PATCH 14/68] stream: add docref param to error functions --- main/streams/php_stream_errors.h | 42 +++++++----- main/streams/plain_wrapper.c | 4 +- main/streams/stream_errors.c | 108 +++++++++++++++++++------------ 3 files changed, 92 insertions(+), 62 deletions(-) diff --git a/main/streams/php_stream_errors.h b/main/streams/php_stream_errors.h index 34894d2512706..ffd0969eef15f 100644 --- a/main/streams/php_stream_errors.h +++ b/main/streams/php_stream_errors.h @@ -122,8 +122,9 @@ BEGIN_EXTERN_C() typedef struct { zend_string *message; int code; - const char *wrapper_name; /* Points to wrapper->wops->label, no need to duplicate */ - const char *param; /* Points to passed string, caller manages lifetime for storage */ + const char *wrapper_name; /* Points to wrapper->wops->label, no need to duplicate */ + const char *docref; + const char *param; int severity; bool terminal; } php_stream_error_entry; @@ -132,17 +133,19 @@ typedef struct { PHPAPI void php_stream_wrapper_error( php_stream_wrapper *wrapper, php_stream_context *context, + const char *docref, int options, int severity, bool terminal, int code, const char *fmt, ... -) ZEND_ATTRIBUTE_FORMAT(printf, 7, 8); +) ZEND_ATTRIBUTE_FORMAT(printf, 8, 9); PHPAPI void php_stream_wrapper_error_param( php_stream_wrapper *wrapper, php_stream_context *context, + const char *docref, int options, int severity, bool terminal, @@ -150,11 +153,12 @@ PHPAPI void php_stream_wrapper_error_param( const char *param, const char *fmt, ... -) ZEND_ATTRIBUTE_FORMAT(printf, 8, 9); +) ZEND_ATTRIBUTE_FORMAT(printf, 9, 10); PHPAPI void php_stream_wrapper_error_param2( php_stream_wrapper *wrapper, php_stream_context *context, + const char *docref, int options, int severity, bool terminal, @@ -163,16 +167,17 @@ PHPAPI void php_stream_wrapper_error_param2( const char *param2, const char *fmt, ... -) ZEND_ATTRIBUTE_FORMAT(printf, 9, 10); +) ZEND_ATTRIBUTE_FORMAT(printf, 10, 11); PHPAPI void php_stream_error( php_stream *stream, + const char *docref, int severity, bool terminal, int code, const char *fmt, ... -) ZEND_ATTRIBUTE_FORMAT(printf, 5, 6); +) ZEND_ATTRIBUTE_FORMAT(printf, 6, 7); /* Legacy wrapper error log - updated API */ PHPAPI void php_stream_wrapper_log_error( @@ -211,37 +216,40 @@ void php_stream_tidy_wrapper_error_log(php_stream_wrapper *wrapper); /* Convenience macros */ #define php_stream_wrapper_warn(wrapper, context, options, code, ...) \ - php_stream_wrapper_error(wrapper, context, options, E_WARNING, true, code, __VA_ARGS__) + php_stream_wrapper_error(wrapper, context, NULL, options, E_WARNING, true, code, __VA_ARGS__) #define php_stream_wrapper_warn_nt(wrapper, context, options, code, ...) \ - php_stream_wrapper_error(wrapper, context, options, E_WARNING, false, code, __VA_ARGS__) + php_stream_wrapper_error(wrapper, context, NULL, options, E_WARNING, false, code, __VA_ARGS__) #define php_stream_wrapper_notice(wrapper, context, options, code, ...) \ - php_stream_wrapper_error(wrapper, context, options, E_NOTICE, false, code, __VA_ARGS__) + php_stream_wrapper_error(wrapper, context, NULL, options, E_NOTICE, false, code, __VA_ARGS__) #define php_stream_wrapper_warn_param(wrapper, context, options, code, param, ...) \ - php_stream_wrapper_error_param(wrapper, context, options, E_WARNING, true, code, param, __VA_ARGS__) + php_stream_wrapper_error_param(wrapper, context, NULL, options, E_WARNING, true, code, param, __VA_ARGS__) #define php_stream_wrapper_warn_param_nt(wrapper, context, options, code, param, ...) \ - php_stream_wrapper_error_param(wrapper, context, options, E_WARNING, false, code, param, __VA_ARGS__) + php_stream_wrapper_error_param(wrapper, context, NULL, options, E_WARNING, false, code, param, __VA_ARGS__) #define php_stream_wrapper_warn_param2(wrapper, context, options, code, param1, param2, ...) \ - php_stream_wrapper_error_param2(wrapper, context, options, E_WARNING, true, code, param1, param2, __VA_ARGS__) + php_stream_wrapper_error_param2(wrapper, context, NULL, options, E_WARNING, true, code, param1, param2, __VA_ARGS__) #define php_stream_wrapper_warn_param2_nt(wrapper, context, options, code, param1, param2, ...) \ - php_stream_wrapper_error_param2(wrapper, context, options, E_WARNING, false, code, param1, param2, __VA_ARGS__) + php_stream_wrapper_error_param2(wrapper, context, NULL, options, E_WARNING, false, code, param1, param2, __VA_ARGS__) #define php_stream_warn(stream, code, ...) \ - php_stream_error(stream, E_WARNING, true, code, __VA_ARGS__) + php_stream_error(stream, NULL, E_WARNING, true, code, __VA_ARGS__) #define php_stream_warn_nt(stream, code, ...) \ - php_stream_error(stream, E_WARNING, false, code, __VA_ARGS__) + php_stream_error(stream, NULL, E_WARNING, false, code, __VA_ARGS__) + +#define php_stream_warn_docref(stream, docref, code, ...) \ + php_stream_error(stream, docref, E_WARNING, true, code, __VA_ARGS__) #define php_stream_notice(stream, code, ...) \ - php_stream_error(stream, E_NOTICE, false, code, __VA_ARGS__) + php_stream_error(stream, NULL, E_NOTICE, false, code, __VA_ARGS__) #define php_stream_fatal(stream, code, ...) \ - php_stream_error(stream, E_ERROR, true, code, __VA_ARGS__) + php_stream_error(stream, NULL, E_ERROR, true, code, __VA_ARGS__) /* Legacy log variants */ #define php_stream_wrapper_log_warn(wrapper, context, options, code, ...) \ diff --git a/main/streams/plain_wrapper.c b/main/streams/plain_wrapper.c index d71e706f847e7..c3f6128656d07 100644 --- a/main/streams/plain_wrapper.c +++ b/main/streams/plain_wrapper.c @@ -1387,7 +1387,7 @@ static int php_plain_files_rename(php_stream_wrapper *wrapper, const char *url_f if (errno != EPERM) { success = 0; } - php_stream_wrapper_error_param2(wrapper, context, options, E_WARNING, + php_stream_wrapper_error_param2(wrapper, context, NULL, options, E_WARNING, !success, STREAM_ERROR_CODE_CHOWN_FAILED, url_from, url_to, "%s", php_socket_strerror_s(errno, errstr, sizeof(errstr))); } @@ -1397,7 +1397,7 @@ static int php_plain_files_rename(php_stream_wrapper *wrapper, const char *url_f if (errno != EPERM) { success = 0; } - php_stream_wrapper_error_param2(wrapper, context, options, E_WARNING, + php_stream_wrapper_error_param2(wrapper, context, NULL, options, E_WARNING, !success, STREAM_ERROR_CODE_CHOWN_FAILED, url_from, url_to, "%s", php_socket_strerror_s(errno, errstr, sizeof(errstr))); } diff --git a/main/streams/stream_errors.c b/main/streams/stream_errors.c index 74e3af9a7a1c0..be4faabd1162a 100644 --- a/main/streams/stream_errors.c +++ b/main/streams/stream_errors.c @@ -32,6 +32,8 @@ static void php_stream_error_entry_dtor(void *error) { php_stream_error_entry *entry = *(php_stream_error_entry **) error; zend_string_release(entry->message); + efree(entry->docref); + efree(entry->param); efree(entry); } @@ -132,8 +134,8 @@ static void php_stream_throw_exception( /* Core error processing */ static void php_stream_process_error(php_stream_context *context, const char *wrapper_name, - php_stream *stream, int code, const char *message, const char *param, int severity, - bool terminal) + php_stream *stream, const char *docref, int code, const char *message, const char *param, + int severity, bool terminal) { int error_mode = php_stream_get_error_mode(context); @@ -141,9 +143,9 @@ static void php_stream_process_error(php_stream_context *context, const char *wr switch (error_mode) { case PHP_STREAM_ERROR_MODE_ERROR: if (param) { - php_error_docref1(NULL, param, severity, "%s", message); + php_error_docref1(docref, param, severity, "%s", message); } else { - php_error_docref(NULL, severity, "%s", message); + php_error_docref(docref, severity, "%s", message); } break; @@ -168,7 +170,8 @@ static void php_stream_process_error(php_stream_context *context, const char *wr if (!zend_is_callable_ex(handler, NULL, 0, NULL, &fcc, &is_callable_error)) { if (is_callable_error) { - zend_type_error("stream error handler must be a valid callback, %s", is_callable_error); + zend_type_error( + "stream error handler must be a valid callback, %s", is_callable_error); efree(is_callable_error); } else { zend_type_error("stream error must be a valid callback"); @@ -213,7 +216,8 @@ static void php_stream_process_error(php_stream_context *context, const char *wr /* Helper to create error entry */ static php_stream_error_entry *php_stream_create_error_entry(zend_string *message, int code, - const char *wrapper_name, const char *param, int severity, bool terminal) + const char *wrapper_name, const char *docref, const char *param, int severity, + bool terminal) { php_stream_error_entry *entry = emalloc(sizeof(php_stream_error_entry)); entry->message = message; /* Takes ownership */ @@ -227,18 +231,22 @@ static php_stream_error_entry *php_stream_create_error_entry(zend_string *messag /* Common storage function*/ static void php_stream_store_error_common(php_stream_context *context, php_stream *stream, - php_stream_wrapper *wrapper, zend_string *message, int code, const char *wrapper_name, - const char *param, int severity, bool terminal) + php_stream_wrapper *wrapper, zend_string *message, const char *docref, int code, + const char *wrapper_name, const char *param, int severity, bool terminal) { int error_mode = php_stream_get_error_mode(context); int store_mode = php_stream_get_error_store_mode(context, error_mode); if (!php_stream_should_store_error(store_mode, terminal)) { + efree(param); return; } - php_stream_error_entry *entry - = php_stream_create_error_entry(message, code, wrapper_name, param, severity, terminal); + if (docref != NULL) { + docref = estrdup(docref); + } + php_stream_error_entry *entry = php_stream_create_error_entry( + message, code, wrapper_name, docref, param, severity, terminal); zend_string_addref(message); /* Storage keeps a reference */ zend_llist *list; @@ -277,46 +285,51 @@ static void php_stream_store_error_common(php_stream_context *context, php_strea /* Wrapper error reporting - stores in FG(wrapper_stored_errors) */ static void php_stream_wrapper_error_internal(php_stream_wrapper *wrapper, - php_stream_context *context, int options, int severity, bool terminal, int code, - const char *param, const char *fmt, va_list args) + php_stream_context *context, const char *docref, int options, int severity, bool terminal, + int code, const char *param, const char *fmt, va_list args) { zend_string *message = vstrpprintf(0, fmt, args); const char *wrapper_name = wrapper ? wrapper->wops->label : "unknown"; if (options & REPORT_ERRORS) { - php_stream_process_error( - context, wrapper_name, NULL, code, ZSTR_VAL(message), param, severity, terminal); + php_stream_process_error(context, wrapper_name, NULL, docref, code, ZSTR_VAL(message), + param, severity, terminal); } php_stream_store_error_common( - context, NULL, wrapper, message, code, wrapper_name, param, severity, terminal); + context, NULL, wrapper, message, docref, code, wrapper_name, param, severity, terminal); zend_string_release(message); } PHPAPI void php_stream_wrapper_error(php_stream_wrapper *wrapper, php_stream_context *context, - int options, int severity, bool terminal, int code, const char *fmt, ...) + const char *docref, int options, int severity, bool terminal, int code, const char *fmt, + ...) { va_list args; va_start(args, fmt); php_stream_wrapper_error_internal( - wrapper, context, options, severity, terminal, code, NULL, fmt, args); + wrapper, context, docref, options, severity, terminal, code, NULL, fmt, args); va_end(args); } PHPAPI void php_stream_wrapper_error_param(php_stream_wrapper *wrapper, php_stream_context *context, - int options, int severity, bool terminal, int code, const char *param, const char *fmt, ...) + const char *docref, int options, int severity, bool terminal, int code, const char *param, + const char *fmt, ...) { va_list args; va_start(args, fmt); + if (param = NULL) { + param = estrdup(param); + } php_stream_wrapper_error_internal( - wrapper, context, options, severity, terminal, code, param, fmt, args); + wrapper, context, docref, options, severity, terminal, code, param, fmt, args); va_end(args); } PHPAPI void php_stream_wrapper_error_param2(php_stream_wrapper *wrapper, - php_stream_context *context, int options, int severity, bool terminal, int code, - const char *param1, const char *param2, const char *fmt, ...) + php_stream_context *context, const char *docref, int options, int severity, bool terminal, + int code, const char *param1, const char *param2, const char *fmt, ...) { char *combined_param; spprintf(&combined_param, 0, "%s,%s", param1, param2); @@ -324,10 +337,8 @@ PHPAPI void php_stream_wrapper_error_param2(php_stream_wrapper *wrapper, va_list args; va_start(args, fmt); php_stream_wrapper_error_internal( - wrapper, context, options, severity, terminal, code, combined_param, fmt, args); + wrapper, context, docref, options, severity, terminal, code, combined_param, fmt, args); va_end(args); - - efree(combined_param); } /* Wrapper error logging - stores in FG(wrapper_logged_errors) */ @@ -336,8 +347,11 @@ static void php_stream_wrapper_log_store_error(const php_stream_wrapper *wrapper zend_string *message, int code, const char *wrapper_name, const char *param, int severity, bool terminal) { - php_stream_error_entry *entry - = php_stream_create_error_entry(message, code, wrapper_name, param, severity, terminal); + if (param != NULL) { + param = estrdup(param); + } + php_stream_error_entry *entry = php_stream_create_error_entry( + message, code, wrapper_name, NULL, param, severity, terminal); zend_string_addref(message); if (!FG(wrapper_logged_errors)) { @@ -359,15 +373,17 @@ static void php_stream_wrapper_log_store_error(const php_stream_wrapper *wrapper zend_llist_add_element(list, &entry); } -static void php_stream_wrapper_log_error_internal(const php_stream_wrapper *wrapper, php_stream_context *context, - int options, int severity, bool terminal, int code, const char *param, const char *fmt, va_list args) +static void php_stream_wrapper_log_error_internal(const php_stream_wrapper *wrapper, + php_stream_context *context, int options, int severity, bool terminal, int code, + const char *param, const char *fmt, va_list args) { zend_string *message = vstrpprintf(0, args, args); const char *wrapper_name = wrapper ? wrapper->wops->label : "unknown"; if (options & REPORT_ERRORS) { /* Report immediately using standard error functions */ - php_stream_wrapper_error_internal(wrapper, context, options, severity, terminal, code, param, fmt, args); + php_stream_wrapper_error_internal( + wrapper, context, options, severity, terminal, code, param, fmt, args); zend_string_release(message); } else { /* Store for later display in FG(wrapper_logged_errors) */ @@ -377,21 +393,25 @@ static void php_stream_wrapper_log_error_internal(const php_stream_wrapper *wrap } } -PHPAPI void php_stream_wrapper_log_error(const php_stream_wrapper *wrapper, php_stream_context *context, - int options, int severity, bool terminal, int code, const char *fmt, ...) +PHPAPI void php_stream_wrapper_log_error(const php_stream_wrapper *wrapper, + php_stream_context *context, int options, int severity, bool terminal, int code, + const char *fmt, ...) { va_list args; va_start(args, fmt); - php_stream_wrapper_log_error_internal(wrapper, context, options, severity, terminal, code, NULL, fmt, args); + php_stream_wrapper_log_error_internal( + wrapper, context, options, severity, terminal, code, NULL, fmt, args); va_end(args); } -PHPAPI void php_stream_wrapper_log_error_param(const php_stream_wrapper *wrapper, php_stream_context *context, - int options, int severity, bool terminal, int code, const char *param, const char *fmt, ...) +PHPAPI void php_stream_wrapper_log_error_param(const php_stream_wrapper *wrapper, + php_stream_context *context, int options, int severity, bool terminal, int code, + const char *param, const char *fmt, ...) { va_list args; va_start(args, fmt); - php_stream_wrapper_log_error_internal(wrapper, context, options, severity, terminal, code, param, fmt, args); + php_stream_wrapper_log_error_internal( + wrapper, context, options, severity, terminal, code, param, fmt, args); va_end(args); } @@ -400,12 +420,14 @@ static zend_llist *php_stream_get_wrapper_errors_list(php_stream_wrapper *wrappe if (!FG(wrapper_logged_errors)) { return NULL; } else { - return (zend_llist*) zend_hash_str_find_ptr(FG(wrapper_logged_errors), (const char*)&wrapper, sizeof(wrapper)); + return (zend_llist *) zend_hash_str_find_ptr( + FG(wrapper_logged_errors), (const char *) &wrapper, sizeof(wrapper)); } } /* {{{ wrapper error reporting */ -static void php_stream_display_wrapper_errors(php_stream_wrapper *wrapper, const char *path, const char *caption) +static void php_stream_display_wrapper_errors( + php_stream_wrapper *wrapper, const char *path, const char *caption) { char *tmp; char *msg; @@ -483,8 +505,8 @@ void php_stream_tidy_wrapper_error_log(php_stream_wrapper *wrapper) /* Stream error reporting */ -PHPAPI void php_stream_error( - php_stream *stream, int severity, bool terminal, int code, const char *fmt, ...) +PHPAPI void php_stream_error(php_stream *stream, const char *docref, int severity, bool terminal, + int code, const char *fmt, ...) { va_list args; va_start(args, fmt); @@ -497,12 +519,12 @@ PHPAPI void php_stream_error( php_stream_context *context = PHP_STREAM_CONTEXT(stream); /* Process the error - always report for stream errors */ - php_stream_process_error( - context, wrapper_name, stream, code, ZSTR_VAL(message), NULL, severity, terminal); + php_stream_process_error(context, wrapper_name, stream, docref, code, ZSTR_VAL(message), NULL, + severity, terminal); /* Store error */ - php_stream_store_error_common( - context, stream, wrapper, message, code, wrapper_name, NULL, severity, terminal); + php_stream_store_error_common(context, stream, wrapper, message, docref, code, wrapper_name, + NULL, severity, terminal); zend_string_release(message); } From cf9685f221fdb29af43668193b01c273b824bfa7 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Mon, 17 Nov 2025 13:15:00 +0100 Subject: [PATCH 15/68] stream: convert transport errors --- main/streams/php_stream_errors.h | 7 +++++-- main/streams/transports.c | 32 +++++++++++++++++++------------- 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/main/streams/php_stream_errors.h b/main/streams/php_stream_errors.h index ffd0969eef15f..cb1c69556355b 100644 --- a/main/streams/php_stream_errors.h +++ b/main/streams/php_stream_errors.h @@ -46,8 +46,11 @@ BEGIN_EXTERN_C() #define STREAM_ERROR_CODE_SEEK_NOT_SUPPORTED 13 #define STREAM_ERROR_CODE_FLUSH_FAILED 14 #define STREAM_ERROR_CODE_TRUNCATE_FAILED 15 -#define STREAM_ERROR_CODE_NOT_WRITABLE 16 -#define STREAM_ERROR_CODE_NOT_READABLE 17 +#define STREAM_ERROR_CODE_CONNECT_FAILED 16 +#define STREAM_ERROR_CODE_BIND_FAILED 17 +#define STREAM_ERROR_CODE_LISTEN_FAILED 18 +#define STREAM_ERROR_CODE_NOT_WRITABLE 19 +#define STREAM_ERROR_CODE_NOT_READABLE 20 /* File system operations */ #define STREAM_ERROR_CODE_DISABLED 30 #define STREAM_ERROR_CODE_NOT_FOUND 31 diff --git a/main/streams/transports.c b/main/streams/transports.c index 83297d9a06ceb..ceab9a083de82 100644 --- a/main/streams/transports.c +++ b/main/streams/transports.c @@ -39,13 +39,13 @@ PHPAPI int php_stream_xport_unregister(const char *protocol) return zend_hash_str_del(&xport_hash, protocol, strlen(protocol)); } -#define ERR_REPORT(out_err, fmt, arg) \ +#define ERR_REPORT(code, out_err, fmt, arg) \ if (out_err) { *out_err = strpprintf(0, fmt, arg); } \ - else { php_error_docref(NULL, E_WARNING, fmt, arg); } + else { php_stream_wrapper_warn(NULL, NULL, REPORT_ERRORS, code, fmt, arg); } -#define ERR_RETURN(out_err, local_err, fmt) \ +#define ERR_RETURN(code, out_err, local_err, fmt) \ if (out_err) { *out_err = local_err; } \ - else { php_error_docref(NULL, E_WARNING, fmt, local_err ? ZSTR_VAL(local_err) : "Unspecified error"); \ + else { php_stream_wrapper_warn(NULL, NULL, REPORT_ERRORS, code, fmt, local_err ? ZSTR_VAL(local_err) : "Unspecified error"); \ if (local_err) { zend_string_release_ex(local_err, 0); local_err = NULL; } \ } @@ -116,7 +116,8 @@ PHPAPI php_stream *_php_stream_xport_create(const char *name, size_t namelen, in n = sizeof(wrapper_name) - 1; PHP_STRLCPY(wrapper_name, protocol, sizeof(wrapper_name), n); - ERR_REPORT(error_string, "Unable to find the socket transport \"%s\" - did you forget to enable it when you configured PHP?", + ERR_REPORT(STREAM_ERROR_CODE_WRAPPER_NOT_FOUND, error_string, + "Unable to find the socket transport \"%s\" - did you forget to enable it when you configured PHP?", wrapper_name); return NULL; @@ -125,7 +126,8 @@ PHPAPI php_stream *_php_stream_xport_create(const char *name, size_t namelen, in if (factory == NULL) { /* should never happen */ - php_error_docref(NULL, E_WARNING, "Could not find a factory !?"); + php_stream_wrapper_warn(NULL, context, REPORT_ERRORS, + STREAM_ERROR_CODE_WRAPPER_NOT_FOUND, "Could not find a factory !?"); return NULL; } @@ -146,7 +148,7 @@ PHPAPI php_stream *_php_stream_xport_create(const char *name, size_t namelen, in flags & STREAM_XPORT_CONNECT_ASYNC ? 1 : 0, timeout, &error_text, error_code)) { - ERR_RETURN(error_string, error_text, "connect() failed: %s"); + ERR_RETURN(STREAM_ERROR_CODE_CONNECT_FAILED, error_string, error_text, "connect() failed: %s"); failed = true; } @@ -156,7 +158,7 @@ PHPAPI php_stream *_php_stream_xport_create(const char *name, size_t namelen, in /* server */ if (flags & STREAM_XPORT_BIND) { if (0 != php_stream_xport_bind(stream, name, namelen, &error_text)) { - ERR_RETURN(error_string, error_text, "bind() failed: %s"); + ERR_RETURN(STREAM_ERROR_CODE_BIND_FAILED, error_string, error_text, "bind() failed: %s"); failed = true; } else if (flags & STREAM_XPORT_LISTEN) { zval *zbacklog = NULL; @@ -167,7 +169,7 @@ PHPAPI php_stream *_php_stream_xport_create(const char *name, size_t namelen, in } if (0 != php_stream_xport_listen(stream, backlog, &error_text)) { - ERR_RETURN(error_string, error_text, "listen() failed: %s"); + ERR_RETURN(STREAM_ERROR_CODE_LISTEN_FAILED, error_string, error_text, "listen() failed: %s"); failed = true; } } @@ -370,7 +372,8 @@ PHPAPI int php_stream_xport_crypto_setup(php_stream *stream, php_stream_xport_cr return param.outputs.returncode; } - php_error_docref("streams.crypto", E_WARNING, "This stream does not support SSL/crypto"); + php_stream_warn_docref(stream, "streams.crypto", STREAM_ERROR_CODE_SSL_NOT_SUPPORTED, + "This stream does not support SSL/crypto"); return ret; } @@ -390,7 +393,8 @@ PHPAPI int php_stream_xport_crypto_enable(php_stream *stream, int activate) return param.outputs.returncode; } - php_error_docref("streams.crypto", E_WARNING, "This stream does not support SSL/crypto"); + php_stream_warn_docref(stream, "streams.crypto", STREAM_ERROR_CODE_SSL_NOT_SUPPORTED, + "This stream does not support SSL/crypto"); return ret; } @@ -412,7 +416,8 @@ PHPAPI int php_stream_xport_recvfrom(php_stream *stream, char *buf, size_t bufle } if (stream->readfilters.head) { - php_error_docref(NULL, E_WARNING, "Cannot peek or fetch OOB data from a filtered stream"); + php_stream_warn(stream, STREAM_ERROR_CODE_FILTER_FAILED, + "Cannot peek or fetch OOB data from a filtered stream"); return -1; } @@ -482,7 +487,8 @@ PHPAPI int php_stream_xport_sendto(php_stream *stream, const char *buf, size_t b oob = (flags & STREAM_OOB) == STREAM_OOB; if ((oob || addr) && stream->writefilters.head) { - php_error_docref(NULL, E_WARNING, "Cannot write OOB data, or data to a targeted address on a filtered stream"); + php_stream_warn(stream, STREAM_ERROR_CODE_FILTER_FAILED, + "Cannot write OOB data, or data to a targeted address on a filtered stream"); return -1; } From 0426e3024344d46dc1aa9a9e568895c70d6dc602 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Mon, 17 Nov 2025 15:53:46 +0100 Subject: [PATCH 16/68] stream: store wrapper erros by name instead of ptr --- main/streams/stream_errors.c | 71 ++++++++++++++++++++++-------------- 1 file changed, 44 insertions(+), 27 deletions(-) diff --git a/main/streams/stream_errors.c b/main/streams/stream_errors.c index be4faabd1162a..0879a02c68954 100644 --- a/main/streams/stream_errors.c +++ b/main/streams/stream_errors.c @@ -32,6 +32,7 @@ static void php_stream_error_entry_dtor(void *error) { php_stream_error_entry *entry = *(php_stream_error_entry **) error; zend_string_release(entry->message); + efree(entry->wrapper_name); efree(entry->docref); efree(entry->param); efree(entry); @@ -220,18 +221,22 @@ static php_stream_error_entry *php_stream_create_error_entry(zend_string *messag bool terminal) { php_stream_error_entry *entry = emalloc(sizeof(php_stream_error_entry)); - entry->message = message; /* Takes ownership */ + entry->message = message; entry->code = code; - entry->wrapper_name = wrapper_name; + entry->wrapper_name = wrapper_name ? estrdup(wrapper_name) : NULL; + entry->docref = docref ? estrdup(docref) : NULL; entry->param = param; entry->severity = severity; entry->terminal = terminal; + + zend_string_addref(message); + return entry; } /* Common storage function*/ static void php_stream_store_error_common(php_stream_context *context, php_stream *stream, - php_stream_wrapper *wrapper, zend_string *message, const char *docref, int code, + zend_string *message, const char *docref, int code, const char *wrapper_name, const char *param, int severity, bool terminal) { int error_mode = php_stream_get_error_mode(context); @@ -241,13 +246,8 @@ static void php_stream_store_error_common(php_stream_context *context, php_strea efree(param); return; } - - if (docref != NULL) { - docref = estrdup(docref); - } php_stream_error_entry *entry = php_stream_create_error_entry( message, code, wrapper_name, docref, param, severity, terminal); - zend_string_addref(message); /* Storage keeps a reference */ zend_llist *list; @@ -267,15 +267,15 @@ static void php_stream_store_error_common(php_stream_context *context, php_strea list = NULL; } else { list = zend_hash_str_find_ptr( - FG(wrapper_stored_errors), (const char *) &wrapper, sizeof(wrapper)); + FG(wrapper_stored_errors), wrapper_name, strlen(wrapper_name)); } if (!list) { zend_llist new_list; zend_llist_init( &new_list, sizeof(php_stream_error_entry *), php_stream_error_entry_dtor, 0); - list = zend_hash_str_update_mem(FG(wrapper_stored_errors), (const char *) &wrapper, - sizeof(wrapper), &new_list, sizeof(new_list)); + list = zend_hash_str_update_mem(FG(wrapper_stored_errors), wrapper_name, + strlen(wrapper_name), &new_list, sizeof(new_list)); } } @@ -283,13 +283,11 @@ static void php_stream_store_error_common(php_stream_context *context, php_strea } /* Wrapper error reporting - stores in FG(wrapper_stored_errors) */ - -static void php_stream_wrapper_error_internal(php_stream_wrapper *wrapper, +static void php_stream_wrapper_error_internal_with_name(const char *wrapper_name, php_stream_context *context, const char *docref, int options, int severity, bool terminal, int code, const char *param, const char *fmt, va_list args) { zend_string *message = vstrpprintf(0, fmt, args); - const char *wrapper_name = wrapper ? wrapper->wops->label : "unknown"; if (options & REPORT_ERRORS) { php_stream_process_error(context, wrapper_name, NULL, docref, code, ZSTR_VAL(message), @@ -297,11 +295,32 @@ static void php_stream_wrapper_error_internal(php_stream_wrapper *wrapper, } php_stream_store_error_common( - context, NULL, wrapper, message, docref, code, wrapper_name, param, severity, terminal); + context, NULL, message, docref, code, wrapper_name, param, severity, terminal); zend_string_release(message); } +static void php_stream_wrapper_error_internal(php_stream_wrapper *wrapper, + php_stream_context *context, const char *docref, int options, int severity, bool terminal, + int code, const char *param, const char *fmt, va_list args) +{ + const char *wrapper_name = wrapper ? wrapper->wops->label : "unknown"; + + php_stream_wrapper_error_internal_with_name(wrapper_name, context, docref, options, severity, + terminal, code, param, fmt, args); +} + +PHPAPI void php_stream_wrapper_error_with_name(const char *wrapper_name, + php_stream_context *context, const char *docref, int options, int severity, bool terminal, + int code, const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + php_stream_wrapper_error_internal_with_name( + wrapper_name, context, docref, options, severity, terminal, code, NULL, fmt, args); + va_end(args); +} + PHPAPI void php_stream_wrapper_error(php_stream_wrapper *wrapper, php_stream_context *context, const char *docref, int options, int severity, bool terminal, int code, const char *fmt, ...) @@ -343,16 +362,14 @@ PHPAPI void php_stream_wrapper_error_param2(php_stream_wrapper *wrapper, /* Wrapper error logging - stores in FG(wrapper_logged_errors) */ -static void php_stream_wrapper_log_store_error(const php_stream_wrapper *wrapper, - zend_string *message, int code, const char *wrapper_name, const char *param, int severity, - bool terminal) +static void php_stream_wrapper_log_store_error(zend_string *message, int code, + const char *wrapper_name, const char *param, int severity, bool terminal) { if (param != NULL) { param = estrdup(param); } php_stream_error_entry *entry = php_stream_create_error_entry( message, code, wrapper_name, NULL, param, severity, terminal); - zend_string_addref(message); if (!FG(wrapper_logged_errors)) { ALLOC_HASHTABLE(FG(wrapper_logged_errors)); @@ -360,14 +377,14 @@ static void php_stream_wrapper_log_store_error(const php_stream_wrapper *wrapper } zend_llist *list = zend_hash_str_find_ptr( - FG(wrapper_logged_errors), (const char *) &wrapper, sizeof(wrapper)); + FG(wrapper_logged_errors), wrapper_name, strlen(wrapper_name)); if (!list) { zend_llist new_list; zend_llist_init( &new_list, sizeof(php_stream_error_entry *), php_stream_error_entry_dtor, 0); - list = zend_hash_str_update_mem(FG(wrapper_logged_errors), (const char *) &wrapper, - sizeof(wrapper), &new_list, sizeof(new_list)); + list = zend_hash_str_update_mem(FG(wrapper_logged_errors), wrapper_name, + strlen(wrapper_name), &new_list, sizeof(new_list)); } zend_llist_add_element(list, &entry); @@ -382,13 +399,13 @@ static void php_stream_wrapper_log_error_internal(const php_stream_wrapper *wrap if (options & REPORT_ERRORS) { /* Report immediately using standard error functions */ - php_stream_wrapper_error_internal( - wrapper, context, options, severity, terminal, code, param, fmt, args); + php_stream_wrapper_error_internal_with_name( + wrapper_name, context, NULL, options, severity, terminal, code, param, fmt, args); zend_string_release(message); } else { /* Store for later display in FG(wrapper_logged_errors) */ php_stream_wrapper_log_store_error( - wrapper, message, code, wrapper_name, param, severity, terminal); + message, code, wrapper_name, param, severity, terminal); zend_string_release(message); } } @@ -523,8 +540,8 @@ PHPAPI void php_stream_error(php_stream *stream, const char *docref, int severit severity, terminal); /* Store error */ - php_stream_store_error_common(context, stream, wrapper, message, docref, code, wrapper_name, - NULL, severity, terminal); + php_stream_store_error_common(context, stream, message, docref, code, wrapper_name, NULL, + severity, terminal); zend_string_release(message); } From 6f730f8f9167b50892d4b3ee3d3adeb7aa64f512 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Mon, 17 Nov 2025 16:53:50 +0100 Subject: [PATCH 17/68] stream: convert user stream wrapper errors --- main/streams/php_stream_errors.h | 135 ++++++++-------------- main/streams/stream_errors.stub.php | 30 +++++ main/streams/stream_errors_arginfo.h | 10 +- main/streams/userspace.c | 162 +++++++++++++++++---------- 4 files changed, 186 insertions(+), 151 deletions(-) diff --git a/main/streams/php_stream_errors.h b/main/streams/php_stream_errors.h index cb1c69556355b..f015a01e4994d 100644 --- a/main/streams/php_stream_errors.h +++ b/main/streams/php_stream_errors.h @@ -72,18 +72,20 @@ BEGIN_EXTERN_C() #define STREAM_ERROR_CODE_COPY_FAILED 47 #define STREAM_ERROR_CODE_TOUCH_FAILED 48 #define STREAM_ERROR_CODE_INVALID_MODE 49 -#define STREAM_ERROR_CODE_MODE_NOT_SUPPORTED 50 -#define STREAM_ERROR_CODE_READONLY 51 -#define STREAM_ERROR_CODE_RECURSION_DETECTED 52 +#define STREAM_ERROR_CODE_INVALID_META 50 +#define STREAM_ERROR_CODE_MODE_NOT_SUPPORTED 51 +#define STREAM_ERROR_CODE_READONLY 52 +#define STREAM_ERROR_CODE_RECURSION_DETECTED 53 /* Wrapper/protocol operations */ -#define STREAM_ERROR_CODE_NO_OPENER 70 -#define STREAM_ERROR_CODE_PERSISTENT_NOT_SUPPORTED 71 -#define STREAM_ERROR_CODE_WRAPPER_NOT_FOUND 72 -#define STREAM_ERROR_CODE_WRAPPER_DISABLED 73 -#define STREAM_ERROR_CODE_PROTOCOL_UNSUPPORTED 74 -#define STREAM_ERROR_CODE_WRAPPER_REGISTRATION_FAILED 75 -#define STREAM_ERROR_CODE_WRAPPER_UNREGISTRATION_FAILED 76 -#define STREAM_ERROR_CODE_WRAPPER_RESTORATION_FAILED 77 +#define STREAM_ERROR_CODE_NOT_IMPLEMENTED 70 +#define STREAM_ERROR_CODE_NO_OPENER 71 +#define STREAM_ERROR_CODE_PERSISTENT_NOT_SUPPORTED 72 +#define STREAM_ERROR_CODE_WRAPPER_NOT_FOUND 73 +#define STREAM_ERROR_CODE_WRAPPER_DISABLED 74 +#define STREAM_ERROR_CODE_PROTOCOL_UNSUPPORTED 75 +#define STREAM_ERROR_CODE_WRAPPER_REGISTRATION_FAILED 76 +#define STREAM_ERROR_CODE_WRAPPER_UNREGISTRATION_FAILED 77 +#define STREAM_ERROR_CODE_WRAPPER_RESTORATION_FAILED 78 /* Filter operations */ #define STREAM_ERROR_CODE_FILTER_NOT_FOUND 90 #define STREAM_ERROR_CODE_FILTER_FAILED 91 @@ -120,12 +122,13 @@ BEGIN_EXTERN_C() /* Userspace stream operations */ #define STREAM_ERROR_CODE_USERSPACE_NOT_IMPLEMENTED 160 #define STREAM_ERROR_CODE_USERSPACE_INVALID_RETURN 161 +#define STREAM_ERROR_CODE_USERSPACE_CALL_FAILED 162 /* Stored error entry */ typedef struct { zend_string *message; int code; - const char *wrapper_name; /* Points to wrapper->wops->label, no need to duplicate */ + const char *wrapper_name; const char *docref; const char *param; int severity; @@ -133,84 +136,37 @@ typedef struct { } php_stream_error_entry; /* Main error reporting functions */ -PHPAPI void php_stream_wrapper_error( - php_stream_wrapper *wrapper, - php_stream_context *context, - const char *docref, - int options, - int severity, - bool terminal, - int code, - const char *fmt, - ... -) ZEND_ATTRIBUTE_FORMAT(printf, 8, 9); - -PHPAPI void php_stream_wrapper_error_param( - php_stream_wrapper *wrapper, - php_stream_context *context, - const char *docref, - int options, - int severity, - bool terminal, - int code, - const char *param, - const char *fmt, - ... -) ZEND_ATTRIBUTE_FORMAT(printf, 9, 10); - -PHPAPI void php_stream_wrapper_error_param2( - php_stream_wrapper *wrapper, - php_stream_context *context, - const char *docref, - int options, - int severity, - bool terminal, - int code, - const char *param1, - const char *param2, - const char *fmt, - ... -) ZEND_ATTRIBUTE_FORMAT(printf, 10, 11); - -PHPAPI void php_stream_error( - php_stream *stream, - const char *docref, - int severity, - bool terminal, - int code, - const char *fmt, - ... -) ZEND_ATTRIBUTE_FORMAT(printf, 6, 7); +PHPAPI void php_stream_wrapper_error_with_name(const char *wrapper_name, + php_stream_context *context, const char *docref, int options, int severity, bool terminal, + int code, const char *fmt, ...) ZEND_ATTRIBUTE_FORMAT(printf, 8, 9); + +PHPAPI void php_stream_wrapper_error(php_stream_wrapper *wrapper, php_stream_context *context, + const char *docref, int options, int severity, bool terminal, int code, const char *fmt, + ...) ZEND_ATTRIBUTE_FORMAT(printf, 8, 9); + +PHPAPI void php_stream_wrapper_error_param(php_stream_wrapper *wrapper, php_stream_context *context, + const char *docref, int options, int severity, bool terminal, int code, const char *param, + const char *fmt, ...) ZEND_ATTRIBUTE_FORMAT(printf, 9, 10); + +PHPAPI void php_stream_wrapper_error_param2(php_stream_wrapper *wrapper, + php_stream_context *context, const char *docref, int options, int severity, bool terminal, + int code, const char *param1, const char *param2, const char *fmt, ...) + ZEND_ATTRIBUTE_FORMAT(printf, 10, 11); + +PHPAPI void php_stream_error(php_stream *stream, const char *docref, int severity, bool terminal, + int code, const char *fmt, ...) ZEND_ATTRIBUTE_FORMAT(printf, 6, 7); /* Legacy wrapper error log - updated API */ -PHPAPI void php_stream_wrapper_log_error( - const php_stream_wrapper *wrapper, - php_stream_context *context, - int options, - int severity, - bool terminal, - int code, - const char *fmt, - ... -) ZEND_ATTRIBUTE_FORMAT(printf, 7, 8); - -PHPAPI void php_stream_wrapper_log_error_param( - const php_stream_wrapper *wrapper, - php_stream_context *context, - int options, - int severity, - bool terminal, - int code, - const char *param, - const char *fmt, - ... -) ZEND_ATTRIBUTE_FORMAT(printf, 8, 9); - -PHPAPI void php_stream_display_wrapper_errors( - php_stream_wrapper *wrapper, - const char *path, - const char *caption -); +PHPAPI void php_stream_wrapper_log_error(const php_stream_wrapper *wrapper, + php_stream_context *context, int options, int severity, bool terminal, int code, + const char *fmt, ...) ZEND_ATTRIBUTE_FORMAT(printf, 7, 8); + +PHPAPI void php_stream_wrapper_log_error_param(const php_stream_wrapper *wrapper, + php_stream_context *context, int options, int severity, bool terminal, int code, + const char *param, const char *fmt, ...) ZEND_ATTRIBUTE_FORMAT(printf, 8, 9); + +PHPAPI void php_stream_display_wrapper_errors(php_stream_wrapper *wrapper, + const char *path, const char *caption); PHPAPI void php_stream_tidy_wrapper_error_log(php_stream_wrapper *wrapper); @@ -221,6 +177,9 @@ void php_stream_tidy_wrapper_error_log(php_stream_wrapper *wrapper); #define php_stream_wrapper_warn(wrapper, context, options, code, ...) \ php_stream_wrapper_error(wrapper, context, NULL, options, E_WARNING, true, code, __VA_ARGS__) +#define php_stream_wrapper_warn_name(wrapper_name, context, options, code, ...) \ + php_stream_wrapper_error_with_name(wrapper_name, context, NULL, options, E_WARNING, true, code, __VA_ARGS__) + #define php_stream_wrapper_warn_nt(wrapper, context, options, code, ...) \ php_stream_wrapper_error(wrapper, context, NULL, options, E_WARNING, false, code, __VA_ARGS__) diff --git a/main/streams/stream_errors.stub.php b/main/streams/stream_errors.stub.php index 802a90e00fb8d..8a27e0060fc3d 100644 --- a/main/streams/stream_errors.stub.php +++ b/main/streams/stream_errors.stub.php @@ -51,6 +51,21 @@ public function getWrapperName(): string {} * @cvalue STREAM_ERROR_CODE_TRUNCATE_FAILED */ const STREAM_ERROR_CODE_TRUNCATE_FAILED = UNKNOWN; +/** + * @var int + * @cvalue STREAM_ERROR_CODE_CONNECT_FAILED + */ +const STREAM_ERROR_CODE_CONNECT_FAILED = UNKNOWN; +/** + * @var int + * @cvalue STREAM_ERROR_CODE_BIND_FAILED + */ +const STREAM_ERROR_CODE_BIND_FAILED = UNKNOWN; +/** + * @var int + * @cvalue STREAM_ERROR_CODE_LISTEN_FAILED + */ +const STREAM_ERROR_CODE_LISTEN_FAILED = UNKNOWN; /** * @var int * @cvalue STREAM_ERROR_CODE_NOT_WRITABLE @@ -161,6 +176,11 @@ public function getWrapperName(): string {} * @cvalue STREAM_ERROR_CODE_INVALID_MODE */ const STREAM_ERROR_CODE_INVALID_MODE = UNKNOWN; +/** + * @var int + * @cvalue STREAM_ERROR_CODE_INVALID_META + */ +const STREAM_ERROR_CODE_INVALID_META = UNKNOWN; /** * @var int * @cvalue STREAM_ERROR_CODE_MODE_NOT_SUPPORTED @@ -176,6 +196,11 @@ public function getWrapperName(): string {} * @cvalue STREAM_ERROR_CODE_RECURSION_DETECTED */ const STREAM_ERROR_CODE_RECURSION_DETECTED = UNKNOWN; +/** + * @var int + * @cvalue STREAM_ERROR_CODE_NOT_IMPLEMENTED + */ +const STREAM_ERROR_CODE_NOT_IMPLEMENTED = UNKNOWN; /** * @var int * @cvalue STREAM_ERROR_CODE_NO_OPENER @@ -361,3 +386,8 @@ public function getWrapperName(): string {} * @cvalue STREAM_ERROR_CODE_USERSPACE_INVALID_RETURN */ const STREAM_ERROR_CODE_USERSPACE_INVALID_RETURN = UNKNOWN; +/** + * @var int + * @cvalue STREAM_ERROR_CODE_USERSPACE_CALL_FAILED + */ +const STREAM_ERROR_CODE_USERSPACE_CALL_FAILED = UNKNOWN; diff --git a/main/streams/stream_errors_arginfo.h b/main/streams/stream_errors_arginfo.h index 5859f825c4ee4..523cf64323a0e 100644 --- a/main/streams/stream_errors_arginfo.h +++ b/main/streams/stream_errors_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: c14298e97a4960fe35b7b1b464a5b0b94099897f */ + * Stub hash: faa3f0e64b8388a495ac645fd3eda49c1ed243bd */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_StreamException_getParam, 0, 0, IS_STRING, 1) ZEND_END_ARG_INFO() @@ -26,6 +26,9 @@ static void register_stream_errors_symbols(int module_number) REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_SEEK_NOT_SUPPORTED", STREAM_ERROR_CODE_SEEK_NOT_SUPPORTED, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_FLUSH_FAILED", STREAM_ERROR_CODE_FLUSH_FAILED, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_TRUNCATE_FAILED", STREAM_ERROR_CODE_TRUNCATE_FAILED, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_CONNECT_FAILED", STREAM_ERROR_CODE_CONNECT_FAILED, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_BIND_FAILED", STREAM_ERROR_CODE_BIND_FAILED, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_LISTEN_FAILED", STREAM_ERROR_CODE_LISTEN_FAILED, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_NOT_WRITABLE", STREAM_ERROR_CODE_NOT_WRITABLE, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_NOT_READABLE", STREAM_ERROR_CODE_NOT_READABLE, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_DISABLED", STREAM_ERROR_CODE_DISABLED, CONST_PERSISTENT); @@ -48,9 +51,13 @@ static void register_stream_errors_symbols(int module_number) REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_COPY_FAILED", STREAM_ERROR_CODE_COPY_FAILED, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_TOUCH_FAILED", STREAM_ERROR_CODE_TOUCH_FAILED, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_INVALID_MODE", STREAM_ERROR_CODE_INVALID_MODE, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_INVALID_META", STREAM_ERROR_CODE_INVALID_META, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_MODE_NOT_SUPPORTED", STREAM_ERROR_CODE_MODE_NOT_SUPPORTED, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_READONLY", STREAM_ERROR_CODE_READONLY, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_RECURSION_DETECTED", STREAM_ERROR_CODE_RECURSION_DETECTED, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_NOT_IMPLEMENTED", STREAM_ERROR_CODE_NOT_IMPLEMENTED, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_NO_OPENER", STREAM_ERROR_CODE_NO_OPENER, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_PERSISTENT_NOT_SUPPORTED", STREAM_ERROR_CODE_PERSISTENT_NOT_SUPPORTED, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_WRAPPER_NOT_FOUND", STREAM_ERROR_CODE_WRAPPER_NOT_FOUND, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_WRAPPER_DISABLED", STREAM_ERROR_CODE_WRAPPER_DISABLED, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_PROTOCOL_UNSUPPORTED", STREAM_ERROR_CODE_PROTOCOL_UNSUPPORTED, CONST_PERSISTENT); @@ -86,6 +93,7 @@ static void register_stream_errors_symbols(int module_number) REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_LOCK_NOT_SUPPORTED", STREAM_ERROR_CODE_LOCK_NOT_SUPPORTED, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_USERSPACE_NOT_IMPLEMENTED", STREAM_ERROR_CODE_USERSPACE_NOT_IMPLEMENTED, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_USERSPACE_INVALID_RETURN", STREAM_ERROR_CODE_USERSPACE_INVALID_RETURN, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_USERSPACE_CALL_FAILED", STREAM_ERROR_CODE_USERSPACE_CALL_FAILED, CONST_PERSISTENT); } static zend_class_entry *register_class_StreamException(zend_class_entry *class_entry_Exception) diff --git a/main/streams/userspace.c b/main/streams/userspace.c index f5e25aa96c772..4683dd270ab39 100644 --- a/main/streams/userspace.c +++ b/main/streams/userspace.c @@ -293,7 +293,8 @@ static php_stream *user_wrapper_opener(php_stream_wrapper *wrapper, const char * /* Try to catch bad usage without preventing flexibility */ if (FG(user_stream_current_filename) != NULL && strcmp(filename, FG(user_stream_current_filename)) == 0) { - php_stream_wrapper_log_error(wrapper, options, "infinite recursion prevented"); + php_stream_wrapper_log_warn(wrapper, context, options, + STREAM_ERROR_CODE_RECURSION_DETECTED, "infinite recursion prevented"); return NULL; } FG(user_stream_current_filename) = filename; @@ -334,8 +335,8 @@ static php_stream *user_wrapper_opener(php_stream_wrapper *wrapper, const char * zval_ptr_dtor(&args[0]); if (UNEXPECTED(call_result == FAILURE)) { - php_stream_wrapper_log_error(wrapper, options, "\"%s::" USERSTREAM_OPEN "\" is not implemented", - ZSTR_VAL(us->wrapper->ce->name)); + php_stream_wrapper_log_warn(wrapper, context, options,STREAM_ERROR_CODE_NOT_IMPLEMENTED, + "\"%s::" USERSTREAM_OPEN "\" is not implemented", ZSTR_VAL(us->wrapper->ce->name)); zval_ptr_dtor(&args[3]); goto end; } @@ -357,8 +358,9 @@ static php_stream *user_wrapper_opener(php_stream_wrapper *wrapper, const char * /* set wrapper data to be a reference to our object */ ZVAL_COPY(&stream->wrapperdata, &us->object); } else { - php_stream_wrapper_log_error(wrapper, options, "\"%s::" USERSTREAM_OPEN "\" call failed", - ZSTR_VAL(us->wrapper->ce->name)); + php_stream_wrapper_log_warn(wrapper, context, options, + STREAM_ERROR_CODE_USERSPACE_CALL_FAILED, + "\"%s::" USERSTREAM_OPEN "\" call failed", ZSTR_VAL(us->wrapper->ce->name)); } zval_ptr_dtor(&zretval); @@ -394,7 +396,8 @@ static php_stream *user_wrapper_opendir(php_stream_wrapper *wrapper, const char /* Try to catch bad usage without preventing flexibility */ if (FG(user_stream_current_filename) != NULL && strcmp(filename, FG(user_stream_current_filename)) == 0) { - php_stream_wrapper_log_error(wrapper, options, "infinite recursion prevented"); + php_stream_wrapper_log_warn(wrapper, context, options, + STREAM_ERROR_CODE_RECURSION_DETECTED, "infinite recursion prevented"); return NULL; } FG(user_stream_current_filename) = filename; @@ -419,8 +422,9 @@ static php_stream *user_wrapper_opendir(php_stream_wrapper *wrapper, const char zval_ptr_dtor(&args[0]); if (UNEXPECTED(call_result == FAILURE)) { - php_stream_wrapper_log_error(wrapper, options, "\"%s::" USERSTREAM_DIR_OPEN "\" is not implemented", - ZSTR_VAL(us->wrapper->ce->name)); + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_NOT_IMPLEMENTED, + "\"%s::" USERSTREAM_DIR_OPEN "\" is not implemented", + ZSTR_VAL(us->wrapper->ce->name)); goto end; } /* Exception occurred in call */ @@ -435,8 +439,9 @@ static php_stream *user_wrapper_opendir(php_stream_wrapper *wrapper, const char /* set wrapper data to be a reference to our object */ ZVAL_COPY(&stream->wrapperdata, &us->object); } else { - php_stream_wrapper_log_error(wrapper, options, "\"%s::" USERSTREAM_DIR_OPEN "\" call failed", - ZSTR_VAL(us->wrapper->ce->name)); + php_stream_wrapper_log_warn(wrapper, context, options, + STREAM_ERROR_CODE_USERSPACE_CALL_FAILED, + "\"%s::" USERSTREAM_DIR_OPEN "\" call failed", ZSTR_VAL(us->wrapper->ce->name)); } zval_ptr_dtor(&zretval); @@ -479,10 +484,15 @@ PHP_FUNCTION(stream_wrapper_register) /* We failed. But why? */ if (zend_hash_exists(php_stream_get_url_stream_wrappers_hash(), protocol)) { - php_error_docref(NULL, E_WARNING, "Protocol %s:// is already defined.", ZSTR_VAL(protocol)); + php_stream_wrapper_warn(&uwrap->wrapper, NULL, REPORT_ERRORS, + STREAM_ERROR_CODE_WRAPPER_REGISTRATION_FAILED, + "Protocol %s:// is already defined.", ZSTR_VAL(protocol)); } else { /* Hash doesn't exist so it must have been an invalid protocol scheme */ - php_error_docref(NULL, E_WARNING, "Invalid protocol scheme specified. Unable to register wrapper class %s to %s://", ZSTR_VAL(uwrap->ce->name), ZSTR_VAL(protocol)); + php_stream_wrapper_warn(&uwrap->wrapper, NULL, REPORT_ERRORS, + STREAM_ERROR_CODE_WRAPPER_REGISTRATION_FAILED, + "Invalid protocol scheme specified. Unable to register wrapper class %s to %s://", + ZSTR_VAL(uwrap->ce->name), ZSTR_VAL(protocol)); } zend_list_delete(rsrc); @@ -502,7 +512,9 @@ PHP_FUNCTION(stream_wrapper_unregister) php_stream_wrapper *wrapper = zend_hash_find_ptr(php_stream_get_url_stream_wrappers_hash(), protocol); if (php_unregister_url_stream_wrapper_volatile(protocol) == FAILURE) { /* We failed */ - php_error_docref(NULL, E_WARNING, "Unable to unregister protocol %s://", ZSTR_VAL(protocol)); + php_stream_wrapper_warn(wrapper, NULL, REPORT_ERRORS, + STREAM_ERROR_CODE_WRAPPER_UNREGISTRATION_FAILED, + "Unable to unregister protocol %s://", ZSTR_VAL(protocol)); RETURN_FALSE; } @@ -530,13 +542,17 @@ PHP_FUNCTION(stream_wrapper_restore) global_wrapper_hash = php_stream_get_url_stream_wrappers_hash_global(); if ((wrapper = zend_hash_find_ptr(global_wrapper_hash, protocol)) == NULL) { - php_error_docref(NULL, E_WARNING, "%s:// never existed, nothing to restore", ZSTR_VAL(protocol)); + php_stream_wrapper_warn_name(user_stream_wops.label, NULL, REPORT_ERRORS, + STREAM_ERROR_CODE_WRAPPER_NOT_FOUND, + "%s:// never existed, nothing to restore", ZSTR_VAL(protocol)); RETURN_FALSE; } wrapper_hash = php_stream_get_url_stream_wrappers_hash(); if (wrapper_hash == global_wrapper_hash || zend_hash_find_ptr(wrapper_hash, protocol) == wrapper) { - php_error_docref(NULL, E_NOTICE, "%s:// was never changed, nothing to restore", ZSTR_VAL(protocol)); + php_stream_wrapper_notice(wrapper, NULL, REPORT_ERRORS, + STREAM_ERROR_CODE_WRAPPER_RESTORATION_FAILED, + "%s:// was never changed, nothing to restore", ZSTR_VAL(protocol)); RETURN_TRUE; } @@ -544,7 +560,9 @@ PHP_FUNCTION(stream_wrapper_restore) php_unregister_url_stream_wrapper_volatile(protocol); if (php_register_url_stream_wrapper_volatile(protocol, wrapper) == FAILURE) { - php_error_docref(NULL, E_WARNING, "Unable to restore original %s:// wrapper", ZSTR_VAL(protocol)); + php_stream_wrapper_warn(wrapper, NULL, REPORT_ERRORS, + STREAM_ERROR_CODE_WRAPPER_RESTORATION_FAILED, + "Unable to restore original %s:// wrapper", ZSTR_VAL(protocol)); RETURN_FALSE; } @@ -572,8 +590,8 @@ static ssize_t php_userstreamop_write(php_stream *stream, const char *buf, size_ zval_ptr_dtor(&args[0]); if (UNEXPECTED(call_result == FAILURE)) { - php_error_docref(NULL, E_WARNING, "%s::" USERSTREAM_WRITE " is not implemented!", - ZSTR_VAL(us->wrapper->ce->name)); + php_stream_warn(stream, REPORT_ERRORS, STREAM_ERROR_CODE_NOT_IMPLEMENTED, + "%s::" USERSTREAM_WRITE " is not implemented!", ZSTR_VAL(us->wrapper->ce->name)); } stream->flags &= ~PHP_STREAM_FLAG_NO_FCLOSE; @@ -593,7 +611,9 @@ static ssize_t php_userstreamop_write(php_stream *stream, const char *buf, size_ /* don't allow strange buffer overruns due to bogus return */ if (didwrite > 0 && didwrite > count) { - php_error_docref(NULL, E_WARNING, "%s::" USERSTREAM_WRITE " wrote " ZEND_LONG_FMT " bytes more data than requested (" ZEND_LONG_FMT " written, " ZEND_LONG_FMT " max)", + php_stream_warn_nt(stream, REPORT_ERRORS, STREAM_ERROR_CODE_USERSPACE_INVALID_RETURN, + "%s::" USERSTREAM_WRITE " wrote " ZEND_LONG_FMT " bytes more data than requested (" + ZEND_LONG_FMT " written, " ZEND_LONG_FMT " max)", ZSTR_VAL(us->wrapper->ce->name), (zend_long)(didwrite - count), (zend_long)didwrite, (zend_long)count); didwrite = count; @@ -624,8 +644,8 @@ static ssize_t php_userstreamop_read(php_stream *stream, char *buf, size_t count } if (UNEXPECTED(call_result == FAILURE)) { - php_error_docref(NULL, E_WARNING, "%s::" USERSTREAM_READ " is not implemented!", - ZSTR_VAL(us->wrapper->ce->name)); + php_stream_warn(stream, REPORT_ERRORS, STREAM_ERROR_CODE_NOT_IMPLEMENTED, + "%s::" USERSTREAM_READ " is not implemented!", ZSTR_VAL(us->wrapper->ce->name)); goto err; } @@ -641,8 +661,12 @@ static ssize_t php_userstreamop_read(php_stream *stream, char *buf, size_t count didread = Z_STRLEN(retval); if (didread > 0) { if (didread > count) { - php_error_docref(NULL, E_WARNING, "%s::" USERSTREAM_READ " - read " ZEND_LONG_FMT " bytes more data than requested (" ZEND_LONG_FMT " read, " ZEND_LONG_FMT " max) - excess data will be lost", - ZSTR_VAL(us->wrapper->ce->name), (zend_long)(didread - count), (zend_long)didread, (zend_long)count); + php_stream_warn_nt(stream, REPORT_ERRORS, STREAM_ERROR_CODE_USERSPACE_INVALID_RETURN, + "%s::" USERSTREAM_READ " - read " ZEND_LONG_FMT + " bytes more data than requested (" ZEND_LONG_FMT " read, " + ZEND_LONG_FMT " max) - excess data will be lost", + ZSTR_VAL(us->wrapper->ce->name), (zend_long)(didread - count), + (zend_long)didread, (zend_long)count); didread = count; } memcpy(buf, Z_STRVAL(retval), didread); @@ -658,7 +682,7 @@ static ssize_t php_userstreamop_read(php_stream *stream, char *buf, size_t count zend_string_release_ex(func_name, false); if (UNEXPECTED(call_result == FAILURE)) { - php_error_docref(NULL, E_WARNING, + php_stream_warn(stream, REPORT_ERRORS, STREAM_ERROR_CODE_NOT_IMPLEMENTED, "%s::" USERSTREAM_EOF " is not implemented! Assuming EOF", ZSTR_VAL(us->wrapper->ce->name)); stream->eof = 1; @@ -774,7 +798,8 @@ static int php_userstreamop_seek(php_stream *stream, zend_off_t offset, int when *newoffs = Z_LVAL(retval); ret = 0; } else if (UNEXPECTED(call_result == FAILURE)) { - php_error_docref(NULL, E_WARNING, "%s::" USERSTREAM_TELL " is not implemented!", ZSTR_VAL(us->wrapper->ce->name)); + php_stream_warn(stream, REPORT_ERRORS, STREAM_ERROR_CODE_NOT_IMPLEMENTED, + "%s::" USERSTREAM_TELL " is not implemented!", ZSTR_VAL(us->wrapper->ce->name)); ret = -1; } else { ret = -1; @@ -838,8 +863,8 @@ static int php_userstreamop_stat(php_stream *stream, php_stream_statbuf *ssb) zend_string_release_ex(func_name, false); if (UNEXPECTED(call_result == FAILURE)) { - php_error_docref(NULL, E_WARNING, "%s::" USERSTREAM_STAT " is not implemented!", - ZSTR_VAL(us->wrapper->ce->name)); + php_stream_warn(stream, REPORT_ERRORS, STREAM_ERROR_CODE_NOT_IMPLEMENTED, + "%s::" USERSTREAM_STAT " is not implemented!", ZSTR_VAL(us->wrapper->ce->name)); return -1; } if (UNEXPECTED(Z_ISUNDEF(retval))) { @@ -857,7 +882,7 @@ static int php_userstreamop_stat(php_stream *stream, php_stream_statbuf *ssb) return ret; } -static int user_stream_set_check_liveliness(const php_userstream_data_t *us) +static int user_stream_set_check_liveliness(php_stream *stream, const php_userstream_data_t *us) { zval retval; @@ -866,7 +891,8 @@ static int user_stream_set_check_liveliness(const php_userstream_data_t *us) zend_string_release_ex(func_name, false); if (UNEXPECTED(call_result == FAILURE)) { - php_error_docref(NULL, E_WARNING, + php_stream_warn(stream, REPORT_ERRORS, + STREAM_ERROR_CODE_NOT_IMPLEMENTED, "%s::" USERSTREAM_EOF " is not implemented! Assuming EOF", ZSTR_VAL(us->wrapper->ce->name)); return PHP_STREAM_OPTION_RETURN_ERR; @@ -877,15 +903,16 @@ static int user_stream_set_check_liveliness(const php_userstream_data_t *us) if (EXPECTED(Z_TYPE(retval) == IS_FALSE || Z_TYPE(retval) == IS_TRUE)) { return Z_TYPE(retval) == IS_TRUE ? PHP_STREAM_OPTION_RETURN_ERR : PHP_STREAM_OPTION_RETURN_OK; } else { - php_error_docref(NULL, E_WARNING, - "%s::" USERSTREAM_EOF " value must be of type bool, %s given", + php_stream_warn(stream, REPORT_ERRORS, + STREAM_ERROR_CODE_USERSPACE_INVALID_RETURN, + "%s::" USERSTREAM_EOF " value must be of type bool, %s given", ZSTR_VAL(us->wrapper->ce->name), zend_zval_value_name(&retval)); zval_ptr_dtor(&retval); return PHP_STREAM_OPTION_RETURN_ERR; } } -static int user_stream_set_locking(const php_userstream_data_t *us, int value) +static int user_stream_set_locking(php_stream *stream, const php_userstream_data_t *us, int value) { zval retval; zval zlock; @@ -920,9 +947,8 @@ static int user_stream_set_locking(const php_userstream_data_t *us, int value) /* lock support test (TODO: more check) */ return PHP_STREAM_OPTION_RETURN_OK; } - php_error_docref(NULL, E_WARNING, - "%s::" USERSTREAM_LOCK " is not implemented!", - ZSTR_VAL(us->wrapper->ce->name)); + php_stream_warn(stream, REPORT_ERRORS, STREAM_ERROR_CODE_NOT_IMPLEMENTED, + "%s::" USERSTREAM_LOCK " is not implemented!", ZSTR_VAL(us->wrapper->ce->name)); return PHP_STREAM_OPTION_RETURN_ERR; } if (UNEXPECTED(Z_ISUNDEF(retval))) { @@ -934,14 +960,15 @@ static int user_stream_set_locking(const php_userstream_data_t *us, int value) } // TODO: ext/standard/tests/file/userstreams_004.phpt returns null implicitly for function // Should this warn or not? And should this be considered an error? - //php_error_docref(NULL, E_WARNING, - // "%s::" USERSTREAM_LOCK " value must be of type bool, %s given", + //php_stream_warn(stream, REPORT_ERRORS, STREAM_ERROR_CODE_USERSPACE_INVALID_RETURN, + // "%s::" USERSTREAM_LOCK " value must be of type bool, %s given", // ZSTR_VAL(us->wrapper->ce->name), zend_zval_value_name(&retval)); zval_ptr_dtor(&retval); return PHP_STREAM_OPTION_RETURN_NOTIMPL; } -static int user_stream_set_truncation(const php_userstream_data_t *us, int value, void *ptrparam) { +static int user_stream_set_truncation(php_stream *stream, const php_userstream_data_t *us, + int value, void *ptrparam) { zend_string *func_name = ZSTR_INIT_LITERAL(USERSTREAM_TRUNCATE, false); if (value == PHP_STREAM_TRUNCATE_SUPPORTED) { @@ -969,9 +996,8 @@ static int user_stream_set_truncation(const php_userstream_data_t *us, int value zend_string_release_ex(func_name, false); if (UNEXPECTED(call_result == FAILURE)) { - php_error_docref(NULL, E_WARNING, - "%s::" USERSTREAM_TRUNCATE " is not implemented!", - ZSTR_VAL(us->wrapper->ce->name)); + php_stream_warn(stream, REPORT_ERRORS, STREAM_ERROR_CODE_NOT_IMPLEMENTED, + "%s::" USERSTREAM_TRUNCATE " is not implemented!", ZSTR_VAL(us->wrapper->ce->name)); return PHP_STREAM_OPTION_RETURN_ERR; } if (UNEXPECTED(Z_ISUNDEF(retval))) { @@ -980,15 +1006,16 @@ static int user_stream_set_truncation(const php_userstream_data_t *us, int value if (EXPECTED(Z_TYPE(retval) == IS_FALSE || Z_TYPE(retval) == IS_TRUE)) { return Z_TYPE(retval) == IS_TRUE ? PHP_STREAM_OPTION_RETURN_OK : PHP_STREAM_OPTION_RETURN_ERR; } else { - php_error_docref(NULL, E_WARNING, - "%s::" USERSTREAM_TRUNCATE " value must be of type bool, %s given", + php_stream_warn(stream, REPORT_ERRORS, STREAM_ERROR_CODE_USERSPACE_INVALID_RETURN, + "%s::" USERSTREAM_TRUNCATE " value must be of type bool, %s given", ZSTR_VAL(us->wrapper->ce->name), zend_zval_value_name(&retval)); zval_ptr_dtor(&retval); return PHP_STREAM_OPTION_RETURN_ERR; } } -static int user_stream_set_option(const php_userstream_data_t *us, int option, int value, void *ptrparam) +static int user_stream_set_option(php_stream *stream, const php_userstream_data_t *us, int option, + int value, void *ptrparam) { zval args[3]; ZVAL_LONG(&args[0], option); @@ -1013,7 +1040,7 @@ static int user_stream_set_option(const php_userstream_data_t *us, int option, i zend_string_release_ex(func_name, false); if (UNEXPECTED(call_result == FAILURE)) { - php_error_docref(NULL, E_WARNING, + php_stream_warn(stream, REPORT_ERRORS, STREAM_ERROR_CODE_NOT_IMPLEMENTED, "%s::" USERSTREAM_SET_OPTION " is not implemented!", ZSTR_VAL(us->wrapper->ce->name)); return PHP_STREAM_OPTION_RETURN_ERR; @@ -1038,19 +1065,19 @@ static int php_userstreamop_set_option(php_stream *stream, int option, int value switch (option) { case PHP_STREAM_OPTION_CHECK_LIVENESS: - return user_stream_set_check_liveliness(us); + return user_stream_set_check_liveliness(stream, us); case PHP_STREAM_OPTION_LOCKING: - return user_stream_set_locking(us, value); + return user_stream_set_locking(stream, us, value); case PHP_STREAM_OPTION_TRUNCATE_API: - return user_stream_set_truncation(us, value, ptrparam); + return user_stream_set_truncation(stream, us, value, ptrparam); case PHP_STREAM_OPTION_READ_BUFFER: case PHP_STREAM_OPTION_WRITE_BUFFER: case PHP_STREAM_OPTION_READ_TIMEOUT: case PHP_STREAM_OPTION_BLOCKING: - return user_stream_set_option(us, option, value, ptrparam); + return user_stream_set_option(stream, us, option, value, ptrparam); default: return PHP_STREAM_OPTION_RETURN_NOTIMPL; @@ -1083,7 +1110,8 @@ static int user_wrapper_unlink(php_stream_wrapper *wrapper, const char *url, int zval_ptr_dtor(&object); if (UNEXPECTED(call_result == FAILURE)) { - php_error_docref(NULL, E_WARNING, "%s::" USERSTREAM_UNLINK " is not implemented!", ZSTR_VAL(uwrap->ce->name)); + php_stream_wrapper_warn(wrapper, context, REPORT_ERRORS, STREAM_ERROR_CODE_NOT_IMPLEMENTED, + "%s::" USERSTREAM_UNLINK " is not implemented!", ZSTR_VAL(uwrap->ce->name)); } else if (Z_TYPE(zretval) == IS_FALSE || Z_TYPE(zretval) == IS_TRUE) { ret = Z_TYPE(zretval) == IS_TRUE; } @@ -1121,7 +1149,8 @@ static int user_wrapper_rename(php_stream_wrapper *wrapper, const char *url_from zval_ptr_dtor(&object); if (UNEXPECTED(call_result == FAILURE)) { - php_error_docref(NULL, E_WARNING, "%s::" USERSTREAM_RENAME " is not implemented!", ZSTR_VAL(uwrap->ce->name)); + php_stream_wrapper_warn(wrapper, context, REPORT_ERRORS, STREAM_ERROR_CODE_NOT_IMPLEMENTED, + "%s::" USERSTREAM_RENAME " is not implemented!", ZSTR_VAL(uwrap->ce->name)); } else if (Z_TYPE(zretval) == IS_FALSE || Z_TYPE(zretval) == IS_TRUE) { ret = Z_TYPE(zretval) == IS_TRUE; } @@ -1159,7 +1188,8 @@ static int user_wrapper_mkdir(php_stream_wrapper *wrapper, const char *url, int zval_ptr_dtor(&object); if (UNEXPECTED(call_result == FAILURE)) { - php_error_docref(NULL, E_WARNING, "%s::" USERSTREAM_MKDIR " is not implemented!", ZSTR_VAL(uwrap->ce->name)); + php_stream_wrapper_warn(wrapper, context, REPORT_ERRORS, STREAM_ERROR_CODE_NOT_IMPLEMENTED, + "%s::" USERSTREAM_MKDIR " is not implemented!", ZSTR_VAL(uwrap->ce->name)); } else if (Z_TYPE(zretval) == IS_FALSE || Z_TYPE(zretval) == IS_TRUE) { ret = Z_TYPE(zretval) == IS_TRUE; } @@ -1196,7 +1226,8 @@ static int user_wrapper_rmdir(php_stream_wrapper *wrapper, const char *url, zval_ptr_dtor(&object); if (UNEXPECTED(call_result == FAILURE)) { - php_error_docref(NULL, E_WARNING, "%s::" USERSTREAM_RMDIR " is not implemented!", ZSTR_VAL(uwrap->ce->name)); + php_stream_wrapper_warn(wrapper, context, REPORT_ERRORS, STREAM_ERROR_CODE_NOT_IMPLEMENTED, + "%s::" USERSTREAM_RMDIR " is not implemented!", ZSTR_VAL(uwrap->ce->name)); } else if (Z_TYPE(zretval) == IS_FALSE || Z_TYPE(zretval) == IS_TRUE) { ret = Z_TYPE(zretval) == IS_TRUE; } @@ -1235,7 +1266,9 @@ static int user_wrapper_metadata(php_stream_wrapper *wrapper, const char *url, i ZVAL_STRING(&args[2], value); break; default: - php_error_docref(NULL, E_WARNING, "Unknown option %d for " USERSTREAM_METADATA, option); + php_stream_wrapper_warn(wrapper, context, REPORT_ERRORS, + STREAM_ERROR_CODE_INVALID_META, + "Unknown option %d for " USERSTREAM_METADATA, option); return ret; } @@ -1258,7 +1291,8 @@ static int user_wrapper_metadata(php_stream_wrapper *wrapper, const char *url, i zval_ptr_dtor(&object); if (UNEXPECTED(call_result == FAILURE)) { - php_error_docref(NULL, E_WARNING, "%s::" USERSTREAM_METADATA " is not implemented!", ZSTR_VAL(uwrap->ce->name)); + php_stream_wrapper_warn(wrapper, context, REPORT_ERRORS, STREAM_ERROR_CODE_NOT_IMPLEMENTED, + "%s::" USERSTREAM_METADATA " is not implemented!", ZSTR_VAL(uwrap->ce->name)); } else if (Z_TYPE(zretval) == IS_FALSE || Z_TYPE(zretval) == IS_TRUE) { ret = Z_TYPE(zretval) == IS_TRUE; } @@ -1296,8 +1330,8 @@ static int user_wrapper_stat_url(php_stream_wrapper *wrapper, const char *url, i zval_ptr_dtor(&object); if (UNEXPECTED(call_result == FAILURE)) { - php_error_docref(NULL, E_WARNING, "%s::" USERSTREAM_STATURL " is not implemented!", - ZSTR_VAL(uwrap->ce->name)); + php_stream_wrapper_warn(wrapper, context, REPORT_ERRORS, STREAM_ERROR_CODE_NOT_IMPLEMENTED, + "%s::" USERSTREAM_STATURL " is not implemented!", ZSTR_VAL(uwrap->ce->name)); return -1; } if (UNEXPECTED(Z_ISUNDEF(zretval))) { @@ -1332,8 +1366,9 @@ static ssize_t php_userstreamop_readdir(php_stream *stream, char *buf, size_t co zend_string_release_ex(func_name, false); if (UNEXPECTED(call_result == FAILURE)) { - php_error_docref(NULL, E_WARNING, "%s::" USERSTREAM_DIR_READ " is not implemented!", - ZSTR_VAL(us->wrapper->ce->name)); + php_stream_warn(stream, REPORT_ERRORS, STREAM_ERROR_CODE_NOT_IMPLEMENTED, + "%s::" USERSTREAM_DIR_READ " is not implemented!", + ZSTR_VAL(us->wrapper->ce->name)); return -1; } if (UNEXPECTED(Z_ISUNDEF(retval))) { @@ -1418,7 +1453,8 @@ static int php_userstreamop_cast(php_stream *stream, int castas, void **retptr) if (UNEXPECTED(call_result == FAILURE)) { if (report_errors) { - php_error_docref(NULL, E_WARNING, "%s::" USERSTREAM_CAST " is not implemented!", + php_stream_warn(stream, REPORT_ERRORS, STREAM_ERROR_CODE_NOT_IMPLEMENTED, + "%s::" USERSTREAM_CAST " is not implemented!", ZSTR_VAL(us->wrapper->ce->name)); } goto out; @@ -1432,14 +1468,16 @@ static int php_userstreamop_cast(php_stream *stream, int castas, void **retptr) php_stream_from_zval_no_verify(intstream, &retval); if (!intstream) { if (report_errors) { - php_error_docref(NULL, E_WARNING, "%s::" USERSTREAM_CAST " must return a stream resource", + php_stream_warn(stream, REPORT_ERRORS, STREAM_ERROR_CODE_USERSPACE_INVALID_RETURN, + "%s::" USERSTREAM_CAST " must return a stream resource", ZSTR_VAL(us->wrapper->ce->name)); } break; } if (intstream == stream) { if (report_errors) { - php_error_docref(NULL, E_WARNING, "%s::" USERSTREAM_CAST " must not return itself", + php_stream_warn(stream, REPORT_ERRORS, STREAM_ERROR_CODE_USERSPACE_INVALID_RETURN, + "%s::" USERSTREAM_CAST " must not return itself", ZSTR_VAL(us->wrapper->ce->name)); } intstream = NULL; From c21470d307e570fdc07570fd808047549b8d113b Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Mon, 17 Nov 2025 17:03:17 +0100 Subject: [PATCH 18/68] stream: convert xp_socket errors --- main/streams/xp_socket.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/main/streams/xp_socket.c b/main/streams/xp_socket.c index f21944313d32a..16e400e1b4f7b 100644 --- a/main/streams/xp_socket.c +++ b/main/streams/xp_socket.c @@ -116,9 +116,8 @@ static ssize_t php_sockop_write(php_stream *stream, const char *buf, size_t coun if (!(stream->flags & PHP_STREAM_FLAG_SUPPRESS_ERRORS)) { estr = php_socket_strerror(err, NULL, 0); - php_error_docref(NULL, E_NOTICE, - "Send of %zu bytes failed with errno=%d %s", - count, err, estr); + php_stream_warn(stream, STREAM_ERROR_CODE_NETWORK_SEND_FAILED, + "Send of %zu bytes failed with errno=%d %s", count, err, estr); efree(estr); } } @@ -454,8 +453,7 @@ static int php_sockop_set_option(php_stream *stream, int option, int value, void xparam->inputs.addrlen); if (xparam->outputs.returncode == -1) { char *err = php_socket_strerror(php_socket_errno(), NULL, 0); - php_error_docref(NULL, E_WARNING, - "%s\n", err); + php_stream_warn(stream, STREAM_ERROR_CODE_NETWORK_SEND_FAILED, "%s", err); efree(err); } return PHP_STREAM_OPTION_RETURN_OK; @@ -595,7 +593,8 @@ static const php_stream_ops php_stream_unixdg_socket_ops = { /* network socket operations */ #ifdef AF_UNIX -static inline int parse_unix_address(php_stream_xport_param *xparam, struct sockaddr_un *unix_addr) +static inline int parse_unix_address(php_stream *stream, php_stream_xport_param *xparam, + struct sockaddr_un *unix_addr) { memset(unix_addr, 0, sizeof(*unix_addr)); unix_addr->sun_family = AF_UNIX; @@ -614,9 +613,9 @@ static inline int parse_unix_address(php_stream_xport_param *xparam, struct sock * BUT, to get into this branch of code, the name is too long, * so we don't care. */ xparam->inputs.namelen = max_length; - php_error_docref(NULL, E_NOTICE, - "socket path exceeded the maximum allowed length of %lu bytes " - "and was truncated", max_length); + php_stream_notice(stream, STREAM_ERROR_CODE_INVALID_PATH, + "socket path exceeded the maximum allowed length of %lu bytes and was truncated", + max_length); } memcpy(unix_addr->sun_path, xparam->inputs.name, xparam->inputs.namelen); @@ -697,7 +696,7 @@ static inline int php_tcp_sockop_bind(php_stream *stream, php_netstream_data_t * return -1; } - parse_unix_address(xparam, &unix_addr); + parse_unix_address(stream, xparam, &unix_addr); int result = bind(sock->socket, (const struct sockaddr *)&unix_addr, (socklen_t) XtOffsetOf(struct sockaddr_un, sun_path) + xparam->inputs.namelen); @@ -833,7 +832,7 @@ static inline int php_tcp_sockop_connect(php_stream *stream, php_netstream_data_ return -1; } - parse_unix_address(xparam, &unix_addr); + parse_unix_address(stream, xparam, &unix_addr); ret = php_network_connect_socket(sock->socket, (const struct sockaddr *)&unix_addr, (socklen_t) XtOffsetOf(struct sockaddr_un, sun_path) + xparam->inputs.namelen, From 2652ff72c4d415fde54c74b0efaf0547239f1512 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Mon, 17 Nov 2025 17:41:03 +0100 Subject: [PATCH 19/68] stream: fix compilation issues in core stream errors --- main/streams/php_stream_errors.h | 6 +++--- main/streams/stream_errors.c | 33 +++++++++++++------------------- 2 files changed, 16 insertions(+), 23 deletions(-) diff --git a/main/streams/php_stream_errors.h b/main/streams/php_stream_errors.h index f015a01e4994d..66d705c2bc3bc 100644 --- a/main/streams/php_stream_errors.h +++ b/main/streams/php_stream_errors.h @@ -128,9 +128,9 @@ BEGIN_EXTERN_C() typedef struct { zend_string *message; int code; - const char *wrapper_name; - const char *docref; - const char *param; + char *wrapper_name; + char *docref; + char *param; int severity; bool terminal; } php_stream_error_entry; diff --git a/main/streams/stream_errors.c b/main/streams/stream_errors.c index 0879a02c68954..ec403acedfe5a 100644 --- a/main/streams/stream_errors.c +++ b/main/streams/stream_errors.c @@ -25,9 +25,6 @@ /* StreamException class entry */ static zend_class_entry *php_ce_stream_exception; -/* Error code registry */ -static HashTable *php_stream_wrapper_error_codes = NULL; - static void php_stream_error_entry_dtor(void *error) { php_stream_error_entry *entry = *(php_stream_error_entry **) error; @@ -217,7 +214,7 @@ static void php_stream_process_error(php_stream_context *context, const char *wr /* Helper to create error entry */ static php_stream_error_entry *php_stream_create_error_entry(zend_string *message, int code, - const char *wrapper_name, const char *docref, const char *param, int severity, + const char *wrapper_name, const char *docref, char *param, int severity, bool terminal) { php_stream_error_entry *entry = emalloc(sizeof(php_stream_error_entry)); @@ -237,7 +234,7 @@ static php_stream_error_entry *php_stream_create_error_entry(zend_string *messag /* Common storage function*/ static void php_stream_store_error_common(php_stream_context *context, php_stream *stream, zend_string *message, const char *docref, int code, - const char *wrapper_name, const char *param, int severity, bool terminal) + const char *wrapper_name, char *param, int severity, bool terminal) { int error_mode = php_stream_get_error_mode(context); int store_mode = php_stream_get_error_store_mode(context, error_mode); @@ -285,7 +282,7 @@ static void php_stream_store_error_common(php_stream_context *context, php_strea /* Wrapper error reporting - stores in FG(wrapper_stored_errors) */ static void php_stream_wrapper_error_internal_with_name(const char *wrapper_name, php_stream_context *context, const char *docref, int options, int severity, bool terminal, - int code, const char *param, const char *fmt, va_list args) + int code, char *param, const char *fmt, va_list args) { zend_string *message = vstrpprintf(0, fmt, args); @@ -302,7 +299,7 @@ static void php_stream_wrapper_error_internal_with_name(const char *wrapper_name static void php_stream_wrapper_error_internal(php_stream_wrapper *wrapper, php_stream_context *context, const char *docref, int options, int severity, bool terminal, - int code, const char *param, const char *fmt, va_list args) + int code, char *param, const char *fmt, va_list args) { const char *wrapper_name = wrapper ? wrapper->wops->label : "unknown"; @@ -338,11 +335,9 @@ PHPAPI void php_stream_wrapper_error_param(php_stream_wrapper *wrapper, php_stre { va_list args; va_start(args, fmt); - if (param = NULL) { - param = estrdup(param); - } + char *param_copy = param ? estrdup(param): NULL; php_stream_wrapper_error_internal( - wrapper, context, docref, options, severity, terminal, code, param, fmt, args); + wrapper, context, docref, options, severity, terminal, code, param_copy, fmt, args); va_end(args); } @@ -365,11 +360,9 @@ PHPAPI void php_stream_wrapper_error_param2(php_stream_wrapper *wrapper, static void php_stream_wrapper_log_store_error(zend_string *message, int code, const char *wrapper_name, const char *param, int severity, bool terminal) { - if (param != NULL) { - param = estrdup(param); - } + char *param_copy = param ? estrdup(param): NULL; php_stream_error_entry *entry = php_stream_create_error_entry( - message, code, wrapper_name, NULL, param, severity, terminal); + message, code, wrapper_name, NULL, param_copy, severity, terminal); if (!FG(wrapper_logged_errors)) { ALLOC_HASHTABLE(FG(wrapper_logged_errors)); @@ -392,9 +385,9 @@ static void php_stream_wrapper_log_store_error(zend_string *message, int code, static void php_stream_wrapper_log_error_internal(const php_stream_wrapper *wrapper, php_stream_context *context, int options, int severity, bool terminal, int code, - const char *param, const char *fmt, va_list args) + char *param, const char *fmt, va_list args) { - zend_string *message = vstrpprintf(0, args, args); + zend_string *message = vstrpprintf(0, fmt, args); const char *wrapper_name = wrapper ? wrapper->wops->label : "unknown"; if (options & REPORT_ERRORS) { @@ -427,8 +420,9 @@ PHPAPI void php_stream_wrapper_log_error_param(const php_stream_wrapper *wrapper { va_list args; va_start(args, fmt); + char *param_copy = param ? estrdup(param): NULL; php_stream_wrapper_log_error_internal( - wrapper, context, options, severity, terminal, code, param, fmt, args); + wrapper, context, options, severity, terminal, code, param_copy, fmt, args); va_end(args); } @@ -442,8 +436,7 @@ static zend_llist *php_stream_get_wrapper_errors_list(php_stream_wrapper *wrappe } } -/* {{{ wrapper error reporting */ -static void php_stream_display_wrapper_errors( +void php_stream_display_wrapper_errors( php_stream_wrapper *wrapper, const char *path, const char *caption) { char *tmp; From 2ced095f41c5e7c3d8552768521d3731bb75e475 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Mon, 17 Nov 2025 19:51:55 +0100 Subject: [PATCH 20/68] stream: extend and fix php_stream_display_wrapper_errors --- main/streams/php_stream_errors.h | 5 +---- main/streams/stream_errors.c | 9 +++++---- main/streams/streams.c | 6 ++++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/main/streams/php_stream_errors.h b/main/streams/php_stream_errors.h index 66d705c2bc3bc..9a926c952c520 100644 --- a/main/streams/php_stream_errors.h +++ b/main/streams/php_stream_errors.h @@ -166,13 +166,10 @@ PHPAPI void php_stream_wrapper_log_error_param(const php_stream_wrapper *wrapper const char *param, const char *fmt, ...) ZEND_ATTRIBUTE_FORMAT(printf, 8, 9); PHPAPI void php_stream_display_wrapper_errors(php_stream_wrapper *wrapper, - const char *path, const char *caption); + php_stream_context *context, int code, const char *path, const char *caption); PHPAPI void php_stream_tidy_wrapper_error_log(php_stream_wrapper *wrapper); -void php_stream_display_wrapper_errors(php_stream_wrapper *wrapper, const char *path, const char *caption); -void php_stream_tidy_wrapper_error_log(php_stream_wrapper *wrapper); - /* Convenience macros */ #define php_stream_wrapper_warn(wrapper, context, options, code, ...) \ php_stream_wrapper_error(wrapper, context, NULL, options, E_WARNING, true, code, __VA_ARGS__) diff --git a/main/streams/stream_errors.c b/main/streams/stream_errors.c index ec403acedfe5a..4c69b4a72ddf2 100644 --- a/main/streams/stream_errors.c +++ b/main/streams/stream_errors.c @@ -436,8 +436,8 @@ static zend_llist *php_stream_get_wrapper_errors_list(php_stream_wrapper *wrappe } } -void php_stream_display_wrapper_errors( - php_stream_wrapper *wrapper, const char *path, const char *caption) +void php_stream_display_wrapper_errors(php_stream_wrapper *wrapper, + php_stream_context *context, int code, const char *path, const char *caption) { char *tmp; char *msg; @@ -471,7 +471,7 @@ void php_stream_display_wrapper_errors( for (err_entry_p = zend_llist_get_first_ex(err_list, &pos), i = 0; err_entry_p; err_entry_p = zend_llist_get_next_ex(err_list, &pos), i++) { - strcat(msg, ZSTR_VAL((*err_entry_p)->message)); + l += ZSTR_LEN((*err_entry_p)->message); if (i < count - 1) { l += brlen; } @@ -499,7 +499,8 @@ void php_stream_display_wrapper_errors( } php_strip_url_passwd(tmp); - php_error_docref1(NULL, tmp, E_WARNING, "%s: %s", caption, msg); + php_stream_wrapper_warn_param(wrapper, context, REPORT_ERRORS, code, tmp, + "%s: %s", caption, msg); efree(tmp); if (free_msg) { efree(msg); diff --git a/main/streams/streams.c b/main/streams/streams.c index c38af809d1a6a..130844503e7f3 100644 --- a/main/streams/streams.c +++ b/main/streams/streams.c @@ -2066,7 +2066,8 @@ PHPAPI php_stream *_php_stream_opendir(const char *path, int options, STREAM_ERROR_CODE_NO_OPENER, "not implemented"); } if (stream == NULL && (options & REPORT_ERRORS)) { - php_stream_display_wrapper_errors(wrapper, path, "Failed to open directory"); + php_stream_display_wrapper_errors(wrapper, context, path, STREAM_ERROR_CODE_OPEN_FAILED, + "Failed to open directory"); } php_stream_tidy_wrapper_error_log(wrapper); @@ -2233,7 +2234,8 @@ PHPAPI php_stream *_php_stream_open_wrapper_ex(const char *path, const char *mod } if (stream == NULL && (options & REPORT_ERRORS)) { - php_stream_display_wrapper_errors(wrapper, path, "Failed to open stream"); + php_stream_display_wrapper_errors(wrapper, context, path, STREAM_ERROR_CODE_OPEN_FAILED, + "Failed to open stream"); if (opened_path && *opened_path) { zend_string_release_ex(*opened_path, 0); *opened_path = NULL; From ea1b31c11db86987006b5d970dd326ebbbfe51a7 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Mon, 17 Nov 2025 20:13:33 +0100 Subject: [PATCH 21/68] stream: fix phar errors --- ext/phar/dirstream.c | 6 +++--- ext/phar/dirstream.h | 2 +- ext/phar/stream.c | 30 +++++++++++++++--------------- ext/phar/stream.h | 2 +- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/ext/phar/dirstream.c b/ext/phar/dirstream.c index 6ea3f7ba2fb06..e364300b0b5f3 100644 --- a/ext/phar/dirstream.c +++ b/ext/phar/dirstream.c @@ -253,7 +253,7 @@ php_stream *phar_wrapper_open_dir(php_stream_wrapper *wrapper, const char *path, char *error; phar_archive_data *phar; - if ((resource = phar_parse_url(wrapper, path, mode, options)) == NULL) { + if ((resource = phar_parse_url(wrapper, context, path, mode, options)) == NULL) { php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_INVALID_URL, "phar url \"%s\" is unknown", path); return NULL; @@ -376,7 +376,7 @@ int phar_wrapper_mkdir(php_stream_wrapper *wrapper, const char *url_from, int mo return 0; } - if ((resource = phar_parse_url(wrapper, url_from, "w", options)) == NULL) { + if ((resource = phar_parse_url(wrapper, context, url_from, "w", options)) == NULL) { return 0; } @@ -520,7 +520,7 @@ int phar_wrapper_rmdir(php_stream_wrapper *wrapper, const char *url, int options return 0; } - if ((resource = phar_parse_url(wrapper, url, "w", options)) == NULL) { + if ((resource = phar_parse_url(wrapper, context, url, "w", options)) == NULL) { return 0; } diff --git a/ext/phar/dirstream.h b/ext/phar/dirstream.h index 4debfecde41a1..42d79c6fc21e9 100644 --- a/ext/phar/dirstream.h +++ b/ext/phar/dirstream.h @@ -24,7 +24,7 @@ int phar_wrapper_rmdir(php_stream_wrapper *wrapper, const char *url, int options #ifdef PHAR_DIRSTREAM #include "ext/standard/url.h" -php_url* phar_parse_url(php_stream_wrapper *wrapper, const char *filename, const char *mode, int options); +php_url* phar_parse_url(php_stream_wrapper *wrapper, php_stream_context *context, const char *filename, const char *mode, int options); /* directory handlers */ static ssize_t phar_dir_write(php_stream *stream, const char *buf, size_t count); diff --git a/ext/phar/stream.c b/ext/phar/stream.c index 98e8a3322c488..df993de3e6d6d 100644 --- a/ext/phar/stream.c +++ b/ext/phar/stream.c @@ -57,7 +57,8 @@ const php_stream_wrapper php_stream_phar_wrapper = { /** * Open a phar file for streams API */ -php_url* phar_parse_url(php_stream_wrapper *wrapper, const char *filename, const char *mode, int options) /* {{{ */ +php_url* phar_parse_url(php_stream_wrapper *wrapper, php_stream_context *context, + const char *filename, const char *mode, int options) { php_url *resource; char *arch = NULL, *entry = NULL, *error; @@ -68,7 +69,7 @@ php_url* phar_parse_url(php_stream_wrapper *wrapper, const char *filename, const } if (mode[0] == 'a') { if (!(options & PHP_STREAM_URL_STAT_QUIET)) { - php_stream_wrapper_log_warn(wrapper, NULL, options, STREAM_ERROR_CODE_MODE_NOT_SUPPORTED, + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_MODE_NOT_SUPPORTED, "phar error: open mode append not supported"); } return NULL; @@ -76,12 +77,12 @@ php_url* phar_parse_url(php_stream_wrapper *wrapper, const char *filename, const if (phar_split_fname(filename, strlen(filename), &arch, &arch_len, &entry, &entry_len, 2, (mode[0] == 'w' ? 2 : 0)) == FAILURE) { if (!(options & PHP_STREAM_URL_STAT_QUIET)) { if (arch && !entry) { - php_stream_wrapper_log_warn(wrapper, NULL, options, STREAM_ERROR_CODE_INVALID_PATH, + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_INVALID_PATH, "phar error: no directory in \"%s\", must have at least phar://%s/ for root directory (always use full path to a new phar)", filename, arch); arch = NULL; } else { - php_stream_wrapper_log_warn(wrapper, NULL, options, STREAM_ERROR_CODE_INVALID_URL, + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_INVALID_URL, "phar error: invalid url or non-existent phar \"%s\"", filename); } } @@ -115,7 +116,7 @@ php_url* phar_parse_url(php_stream_wrapper *wrapper, const char *filename, const } if (PHAR_G(readonly) && (!pphar || !pphar->is_data)) { if (!(options & PHP_STREAM_URL_STAT_QUIET)) { - php_stream_wrapper_log_warn(wrapper, NULL, options, STREAM_ERROR_CODE_READONLY, + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_READONLY, "phar error: write operations disabled by the php.ini setting phar.readonly"); } php_url_free(resource); @@ -136,7 +137,7 @@ php_url* phar_parse_url(php_stream_wrapper *wrapper, const char *filename, const if (error) { spprintf(&error, 0, "Cannot open cached phar '%s' as writeable, copy on write failed", ZSTR_VAL(resource->host)); if (!(options & PHP_STREAM_URL_STAT_QUIET)) { - php_stream_wrapper_log_warn(wrapper, NULL, options, STREAM_ERROR_CODE_OPEN_FAILED, "%s", error); + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_OPEN_FAILED, "%s", error); } efree(error); } @@ -148,7 +149,7 @@ php_url* phar_parse_url(php_stream_wrapper *wrapper, const char *filename, const { if (error) { if (!(options & PHP_STREAM_URL_STAT_QUIET)) { - php_stream_wrapper_log_warn(wrapper, NULL, options, STREAM_ERROR_CODE_NOT_FOUND, "%s", error); + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_NOT_FOUND, "%s", error); } efree(error); } @@ -158,7 +159,6 @@ php_url* phar_parse_url(php_stream_wrapper *wrapper, const char *filename, const } return resource; } -/* }}} */ /** * used for fopen('phar://...') and company @@ -174,7 +174,7 @@ static php_stream * phar_wrapper_open_url(php_stream_wrapper *wrapper, const cha php_stream *fpf; zval *pzoption, *metadata; - if ((resource = phar_parse_url(wrapper, path, mode, options)) == NULL) { + if ((resource = phar_parse_url(wrapper, context, path, mode, options)) == NULL) { return NULL; } @@ -456,7 +456,7 @@ static ssize_t phar_stream_write(php_stream *stream, const char *buf, size_t cou php_stream_seek(data->fp, data->position + data->zero, SEEK_SET); if (count != php_stream_write(data->fp, buf, count)) { - php_stream_wrapper_log_warn(stream->wrapper, stream->flags, STREAM_ERROR_CODE_WRITE_FAILED, + php_stream_warn(stream, STREAM_ERROR_CODE_WRITE_FAILED, "phar error: Could not write %zu characters to \"%s\" in phar \"%s\"", count, ZSTR_VAL(data->internal_file->filename), data->phar->fname); return -1; @@ -485,7 +485,7 @@ static int phar_stream_flush(php_stream *stream) /* {{{ */ data->internal_file->timestamp = time(0); ret = phar_flush(data->phar, &error); if (error) { - php_stream_wrapper_log_warn(stream->wrapper, REPORT_ERRORS, STREAM_ERROR_CODE_FLUSH_FAILED, "%s", error); + php_stream_warn(stream, STREAM_ERROR_CODE_FLUSH_FAILED, "%s", error); efree(error); } return ret; @@ -577,7 +577,7 @@ static int phar_wrapper_stat(php_stream_wrapper *wrapper, const char *url, int f phar_entry_info *entry; size_t internal_file_len; - if ((resource = phar_parse_url(wrapper, url, "r", flags|PHP_STREAM_URL_STAT_QUIET)) == NULL) { + if ((resource = phar_parse_url(wrapper, context, url, "r", flags|PHP_STREAM_URL_STAT_QUIET)) == NULL) { return FAILURE; } @@ -677,7 +677,7 @@ static int phar_wrapper_unlink(php_stream_wrapper *wrapper, const char *url, int phar_entry_data *idata; phar_archive_data *pphar; - if ((resource = phar_parse_url(wrapper, url, "rb", options)) == NULL) { + if ((resource = phar_parse_url(wrapper, context, url, "rb", options)) == NULL) { php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_UNLINK_FAILED, "phar error: unlink failed"); return 0; @@ -760,7 +760,7 @@ static int phar_wrapper_rename(php_stream_wrapper *wrapper, const char *url_from error = NULL; - if ((resource_from = phar_parse_url(wrapper, url_from, "wb", options|PHP_STREAM_URL_STAT_QUIET)) == NULL) { + if ((resource_from = phar_parse_url(wrapper, context, url_from, "wb", options|PHP_STREAM_URL_STAT_QUIET)) == NULL) { php_stream_wrapper_warn(wrapper, context, options, STREAM_ERROR_CODE_INVALID_URL, "phar error: cannot rename \"%s\" to \"%s\": invalid or non-writable url \"%s\"", url_from, url_to, url_from); @@ -779,7 +779,7 @@ static int phar_wrapper_rename(php_stream_wrapper *wrapper, const char *url_from return 0; } - if ((resource_to = phar_parse_url(wrapper, url_to, "wb", options|PHP_STREAM_URL_STAT_QUIET)) == NULL) { + if ((resource_to = phar_parse_url(wrapper, context, url_to, "wb", options|PHP_STREAM_URL_STAT_QUIET)) == NULL) { php_url_free(resource_from); php_stream_wrapper_warn(wrapper, context, options, STREAM_ERROR_CODE_INVALID_URL, "phar error: cannot rename \"%s\" to \"%s\": invalid or non-writable url \"%s\"", diff --git a/ext/phar/stream.h b/ext/phar/stream.h index 83b395b4cfca3..e39ffb2c10baf 100644 --- a/ext/phar/stream.h +++ b/ext/phar/stream.h @@ -20,7 +20,7 @@ BEGIN_EXTERN_C() #include "ext/standard/url.h" -php_url* phar_parse_url(php_stream_wrapper *wrapper, const char *filename, const char *mode, int options); +php_url* phar_parse_url(php_stream_wrapper *wrapper, php_stream_context *context, const char *filename, const char *mode, int options); ZEND_ATTRIBUTE_NONNULL void phar_entry_remove(phar_entry_data *idata, char **error); static php_stream* phar_wrapper_open_url(php_stream_wrapper *wrapper, const char *path, const char *mode, int options, zend_string **opened_path, php_stream_context *context STREAMS_DC); From 8aa958f42d08ebf553a80d3a04e262d09a8d69de Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Mon, 17 Nov 2025 21:52:41 +0100 Subject: [PATCH 22/68] stream: fix http wrapper errors --- ext/standard/http_fopen_wrapper.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ext/standard/http_fopen_wrapper.c b/ext/standard/http_fopen_wrapper.c index ed209bd7e90e7..a15862d784e94 100644 --- a/ext/standard/http_fopen_wrapper.c +++ b/ext/standard/http_fopen_wrapper.c @@ -287,7 +287,7 @@ static zend_string *php_stream_http_response_headers_parse(php_stream_wrapper *w size_t last_header_value_len = strlen(last_header_value); if (last_header_value_len > HTTP_HEADER_MAX_LOCATION_SIZE) { header_info->error = true; - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_INVALID_RESPONSE, + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_INVALID_RESPONSE, "HTTP Location header size is over the limit of %d bytes", HTTP_HEADER_MAX_LOCATION_SIZE); zend_string_efree(last_header_line_str); @@ -468,7 +468,7 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, #endif if (d > timeoutmax) { - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_INVALID_PARAM, + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_INVALID_PARAM, "timeout must be lower than " ZEND_ULONG_FMT, (zend_ulong)timeoutmax); zend_string_release(transport_string); php_uri_struct_free(resource); @@ -499,7 +499,7 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, } if (errstr) { - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_PROTOCOL_ERROR, + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_PROTOCOL_ERROR, "%s", ZSTR_VAL(errstr)); zend_string_release_ex(errstr, 0); errstr = NULL; @@ -1107,7 +1107,7 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, php_uri_struct_free(resource); /* check for invalid redirection URLs */ if ((resource = php_uri_parse_to_struct(uri_parser, new_path, strlen(new_path), PHP_URI_COMPONENT_READ_MODE_RAW, true)) == NULL) { - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_INVALID_URL, + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_INVALID_URL, "Invalid redirect URL! %s", new_path); efree(new_path); goto out; @@ -1120,7 +1120,7 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, s = (unsigned char*)ZSTR_VAL(val); e = s + ZSTR_LEN(val); \ while (s < e) { \ if (iscntrl(*s)) { \ - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_INVALID_URL, \ + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_INVALID_URL, \ "Invalid redirect URL! %s", new_path); \ efree(new_path); \ goto out; \ @@ -1147,7 +1147,7 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, --redirect_max, new_flags, response_header STREAMS_CC); efree(new_path); } else { - php_stream_wrapper_log_warn(wrapper, options, STREAM_ERROR_CODE_PROTOCOL_ERROR, + php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_PROTOCOL_ERROR, "HTTP request failed! %s", tmp_line); } } From a50519ed6e2307a476c275546139348ceebd5e6b Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Mon, 17 Nov 2025 22:10:13 +0100 Subject: [PATCH 23/68] stream: fix user wrapper error calls --- main/streams/userspace.c | 38 ++++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/main/streams/userspace.c b/main/streams/userspace.c index 4683dd270ab39..4ba3bed83d3be 100644 --- a/main/streams/userspace.c +++ b/main/streams/userspace.c @@ -590,7 +590,7 @@ static ssize_t php_userstreamop_write(php_stream *stream, const char *buf, size_ zval_ptr_dtor(&args[0]); if (UNEXPECTED(call_result == FAILURE)) { - php_stream_warn(stream, REPORT_ERRORS, STREAM_ERROR_CODE_NOT_IMPLEMENTED, + php_stream_warn(stream, STREAM_ERROR_CODE_NOT_IMPLEMENTED, "%s::" USERSTREAM_WRITE " is not implemented!", ZSTR_VAL(us->wrapper->ce->name)); } @@ -611,7 +611,7 @@ static ssize_t php_userstreamop_write(php_stream *stream, const char *buf, size_ /* don't allow strange buffer overruns due to bogus return */ if (didwrite > 0 && didwrite > count) { - php_stream_warn_nt(stream, REPORT_ERRORS, STREAM_ERROR_CODE_USERSPACE_INVALID_RETURN, + php_stream_warn_nt(stream, STREAM_ERROR_CODE_USERSPACE_INVALID_RETURN, "%s::" USERSTREAM_WRITE " wrote " ZEND_LONG_FMT " bytes more data than requested (" ZEND_LONG_FMT " written, " ZEND_LONG_FMT " max)", ZSTR_VAL(us->wrapper->ce->name), @@ -644,7 +644,7 @@ static ssize_t php_userstreamop_read(php_stream *stream, char *buf, size_t count } if (UNEXPECTED(call_result == FAILURE)) { - php_stream_warn(stream, REPORT_ERRORS, STREAM_ERROR_CODE_NOT_IMPLEMENTED, + php_stream_warn(stream, STREAM_ERROR_CODE_NOT_IMPLEMENTED, "%s::" USERSTREAM_READ " is not implemented!", ZSTR_VAL(us->wrapper->ce->name)); goto err; } @@ -661,7 +661,7 @@ static ssize_t php_userstreamop_read(php_stream *stream, char *buf, size_t count didread = Z_STRLEN(retval); if (didread > 0) { if (didread > count) { - php_stream_warn_nt(stream, REPORT_ERRORS, STREAM_ERROR_CODE_USERSPACE_INVALID_RETURN, + php_stream_warn_nt(stream, STREAM_ERROR_CODE_USERSPACE_INVALID_RETURN, "%s::" USERSTREAM_READ " - read " ZEND_LONG_FMT " bytes more data than requested (" ZEND_LONG_FMT " read, " ZEND_LONG_FMT " max) - excess data will be lost", @@ -682,7 +682,7 @@ static ssize_t php_userstreamop_read(php_stream *stream, char *buf, size_t count zend_string_release_ex(func_name, false); if (UNEXPECTED(call_result == FAILURE)) { - php_stream_warn(stream, REPORT_ERRORS, STREAM_ERROR_CODE_NOT_IMPLEMENTED, + php_stream_warn(stream, STREAM_ERROR_CODE_NOT_IMPLEMENTED, "%s::" USERSTREAM_EOF " is not implemented! Assuming EOF", ZSTR_VAL(us->wrapper->ce->name)); stream->eof = 1; @@ -798,7 +798,7 @@ static int php_userstreamop_seek(php_stream *stream, zend_off_t offset, int when *newoffs = Z_LVAL(retval); ret = 0; } else if (UNEXPECTED(call_result == FAILURE)) { - php_stream_warn(stream, REPORT_ERRORS, STREAM_ERROR_CODE_NOT_IMPLEMENTED, + php_stream_warn(stream, STREAM_ERROR_CODE_NOT_IMPLEMENTED, "%s::" USERSTREAM_TELL " is not implemented!", ZSTR_VAL(us->wrapper->ce->name)); ret = -1; } else { @@ -863,7 +863,7 @@ static int php_userstreamop_stat(php_stream *stream, php_stream_statbuf *ssb) zend_string_release_ex(func_name, false); if (UNEXPECTED(call_result == FAILURE)) { - php_stream_warn(stream, REPORT_ERRORS, STREAM_ERROR_CODE_NOT_IMPLEMENTED, + php_stream_warn(stream, STREAM_ERROR_CODE_NOT_IMPLEMENTED, "%s::" USERSTREAM_STAT " is not implemented!", ZSTR_VAL(us->wrapper->ce->name)); return -1; } @@ -891,8 +891,7 @@ static int user_stream_set_check_liveliness(php_stream *stream, const php_userst zend_string_release_ex(func_name, false); if (UNEXPECTED(call_result == FAILURE)) { - php_stream_warn(stream, REPORT_ERRORS, - STREAM_ERROR_CODE_NOT_IMPLEMENTED, + php_stream_warn(stream, STREAM_ERROR_CODE_NOT_IMPLEMENTED, "%s::" USERSTREAM_EOF " is not implemented! Assuming EOF", ZSTR_VAL(us->wrapper->ce->name)); return PHP_STREAM_OPTION_RETURN_ERR; @@ -903,8 +902,7 @@ static int user_stream_set_check_liveliness(php_stream *stream, const php_userst if (EXPECTED(Z_TYPE(retval) == IS_FALSE || Z_TYPE(retval) == IS_TRUE)) { return Z_TYPE(retval) == IS_TRUE ? PHP_STREAM_OPTION_RETURN_ERR : PHP_STREAM_OPTION_RETURN_OK; } else { - php_stream_warn(stream, REPORT_ERRORS, - STREAM_ERROR_CODE_USERSPACE_INVALID_RETURN, + php_stream_warn(stream, STREAM_ERROR_CODE_USERSPACE_INVALID_RETURN, "%s::" USERSTREAM_EOF " value must be of type bool, %s given", ZSTR_VAL(us->wrapper->ce->name), zend_zval_value_name(&retval)); zval_ptr_dtor(&retval); @@ -947,7 +945,7 @@ static int user_stream_set_locking(php_stream *stream, const php_userstream_data /* lock support test (TODO: more check) */ return PHP_STREAM_OPTION_RETURN_OK; } - php_stream_warn(stream, REPORT_ERRORS, STREAM_ERROR_CODE_NOT_IMPLEMENTED, + php_stream_warn(stream, STREAM_ERROR_CODE_NOT_IMPLEMENTED, "%s::" USERSTREAM_LOCK " is not implemented!", ZSTR_VAL(us->wrapper->ce->name)); return PHP_STREAM_OPTION_RETURN_ERR; } @@ -960,7 +958,7 @@ static int user_stream_set_locking(php_stream *stream, const php_userstream_data } // TODO: ext/standard/tests/file/userstreams_004.phpt returns null implicitly for function // Should this warn or not? And should this be considered an error? - //php_stream_warn(stream, REPORT_ERRORS, STREAM_ERROR_CODE_USERSPACE_INVALID_RETURN, + //php_stream_warn(stream, STREAM_ERROR_CODE_USERSPACE_INVALID_RETURN, // "%s::" USERSTREAM_LOCK " value must be of type bool, %s given", // ZSTR_VAL(us->wrapper->ce->name), zend_zval_value_name(&retval)); zval_ptr_dtor(&retval); @@ -996,7 +994,7 @@ static int user_stream_set_truncation(php_stream *stream, const php_userstream_d zend_string_release_ex(func_name, false); if (UNEXPECTED(call_result == FAILURE)) { - php_stream_warn(stream, REPORT_ERRORS, STREAM_ERROR_CODE_NOT_IMPLEMENTED, + php_stream_warn(stream, STREAM_ERROR_CODE_NOT_IMPLEMENTED, "%s::" USERSTREAM_TRUNCATE " is not implemented!", ZSTR_VAL(us->wrapper->ce->name)); return PHP_STREAM_OPTION_RETURN_ERR; } @@ -1006,7 +1004,7 @@ static int user_stream_set_truncation(php_stream *stream, const php_userstream_d if (EXPECTED(Z_TYPE(retval) == IS_FALSE || Z_TYPE(retval) == IS_TRUE)) { return Z_TYPE(retval) == IS_TRUE ? PHP_STREAM_OPTION_RETURN_OK : PHP_STREAM_OPTION_RETURN_ERR; } else { - php_stream_warn(stream, REPORT_ERRORS, STREAM_ERROR_CODE_USERSPACE_INVALID_RETURN, + php_stream_warn(stream, STREAM_ERROR_CODE_USERSPACE_INVALID_RETURN, "%s::" USERSTREAM_TRUNCATE " value must be of type bool, %s given", ZSTR_VAL(us->wrapper->ce->name), zend_zval_value_name(&retval)); zval_ptr_dtor(&retval); @@ -1040,7 +1038,7 @@ static int user_stream_set_option(php_stream *stream, const php_userstream_data_ zend_string_release_ex(func_name, false); if (UNEXPECTED(call_result == FAILURE)) { - php_stream_warn(stream, REPORT_ERRORS, STREAM_ERROR_CODE_NOT_IMPLEMENTED, + php_stream_warn(stream, STREAM_ERROR_CODE_NOT_IMPLEMENTED, "%s::" USERSTREAM_SET_OPTION " is not implemented!", ZSTR_VAL(us->wrapper->ce->name)); return PHP_STREAM_OPTION_RETURN_ERR; @@ -1366,7 +1364,7 @@ static ssize_t php_userstreamop_readdir(php_stream *stream, char *buf, size_t co zend_string_release_ex(func_name, false); if (UNEXPECTED(call_result == FAILURE)) { - php_stream_warn(stream, REPORT_ERRORS, STREAM_ERROR_CODE_NOT_IMPLEMENTED, + php_stream_warn(stream, STREAM_ERROR_CODE_NOT_IMPLEMENTED, "%s::" USERSTREAM_DIR_READ " is not implemented!", ZSTR_VAL(us->wrapper->ce->name)); return -1; @@ -1453,7 +1451,7 @@ static int php_userstreamop_cast(php_stream *stream, int castas, void **retptr) if (UNEXPECTED(call_result == FAILURE)) { if (report_errors) { - php_stream_warn(stream, REPORT_ERRORS, STREAM_ERROR_CODE_NOT_IMPLEMENTED, + php_stream_warn(stream, STREAM_ERROR_CODE_NOT_IMPLEMENTED, "%s::" USERSTREAM_CAST " is not implemented!", ZSTR_VAL(us->wrapper->ce->name)); } @@ -1468,7 +1466,7 @@ static int php_userstreamop_cast(php_stream *stream, int castas, void **retptr) php_stream_from_zval_no_verify(intstream, &retval); if (!intstream) { if (report_errors) { - php_stream_warn(stream, REPORT_ERRORS, STREAM_ERROR_CODE_USERSPACE_INVALID_RETURN, + php_stream_warn(stream, STREAM_ERROR_CODE_USERSPACE_INVALID_RETURN, "%s::" USERSTREAM_CAST " must return a stream resource", ZSTR_VAL(us->wrapper->ce->name)); } @@ -1476,7 +1474,7 @@ static int php_userstreamop_cast(php_stream *stream, int castas, void **retptr) } if (intstream == stream) { if (report_errors) { - php_stream_warn(stream, REPORT_ERRORS, STREAM_ERROR_CODE_USERSPACE_INVALID_RETURN, + php_stream_warn(stream, STREAM_ERROR_CODE_USERSPACE_INVALID_RETURN, "%s::" USERSTREAM_CAST " must not return itself", ZSTR_VAL(us->wrapper->ce->name)); } From db3f377c5407539ccd47f8d3286f404a89559bc7 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Mon, 17 Nov 2025 22:10:27 +0100 Subject: [PATCH 24/68] stream: fix php_stream_display_wrapper_errors usage --- main/streams/streams.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/main/streams/streams.c b/main/streams/streams.c index 130844503e7f3..49154daabea4f 100644 --- a/main/streams/streams.c +++ b/main/streams/streams.c @@ -2066,7 +2066,7 @@ PHPAPI php_stream *_php_stream_opendir(const char *path, int options, STREAM_ERROR_CODE_NO_OPENER, "not implemented"); } if (stream == NULL && (options & REPORT_ERRORS)) { - php_stream_display_wrapper_errors(wrapper, context, path, STREAM_ERROR_CODE_OPEN_FAILED, + php_stream_display_wrapper_errors(wrapper, context, STREAM_ERROR_CODE_OPEN_FAILED, path, "Failed to open directory"); } php_stream_tidy_wrapper_error_log(wrapper); @@ -2234,7 +2234,7 @@ PHPAPI php_stream *_php_stream_open_wrapper_ex(const char *path, const char *mod } if (stream == NULL && (options & REPORT_ERRORS)) { - php_stream_display_wrapper_errors(wrapper, context, path, STREAM_ERROR_CODE_OPEN_FAILED, + php_stream_display_wrapper_errors(wrapper, context, STREAM_ERROR_CODE_OPEN_FAILED, path, "Failed to open stream"); if (opened_path && *opened_path) { zend_string_release_ex(*opened_path, 0); From 3cd9b6dfebf40f8a198870313360109da596f260 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Mon, 17 Nov 2025 22:28:41 +0100 Subject: [PATCH 25/68] stream: fix wrapper selection for displaying logged errors --- main/streams/stream_errors.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/main/streams/stream_errors.c b/main/streams/stream_errors.c index 4c69b4a72ddf2..97e5692a035e5 100644 --- a/main/streams/stream_errors.c +++ b/main/streams/stream_errors.c @@ -426,20 +426,19 @@ PHPAPI void php_stream_wrapper_log_error_param(const php_stream_wrapper *wrapper va_end(args); } -static zend_llist *php_stream_get_wrapper_errors_list(php_stream_wrapper *wrapper) +static zend_llist *php_stream_get_wrapper_errors_list(const char *wrapper_name) { if (!FG(wrapper_logged_errors)) { return NULL; } else { return (zend_llist *) zend_hash_str_find_ptr( - FG(wrapper_logged_errors), (const char *) &wrapper, sizeof(wrapper)); + FG(wrapper_logged_errors), wrapper_name, strlen(wrapper_name)); } } void php_stream_display_wrapper_errors(php_stream_wrapper *wrapper, php_stream_context *context, int code, const char *path, const char *caption) { - char *tmp; char *msg; char errstr[256]; int free_msg = 0; @@ -449,9 +448,10 @@ void php_stream_display_wrapper_errors(php_stream_wrapper *wrapper, return; } - tmp = estrdup(path); + const char *wrapper_name = wrapper ? wrapper->wops->label : "unknown"; + char *tmp = estrdup(path); if (wrapper) { - zend_llist *err_list = php_stream_get_wrapper_errors_list(wrapper); + zend_llist *err_list = php_stream_get_wrapper_errors_list(wrapper_name); if (err_list) { size_t l = 0; int brlen; From 03902bed7aa4ee99f2380494a8642954501b27d2 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Tue, 18 Nov 2025 10:58:40 +0100 Subject: [PATCH 26/68] stream: fix wrapper key in php_stream_tidy_wrapper_error_log --- main/streams/stream_errors.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/main/streams/stream_errors.c b/main/streams/stream_errors.c index 97e5692a035e5..6fad781750d2a 100644 --- a/main/streams/stream_errors.c +++ b/main/streams/stream_errors.c @@ -510,7 +510,8 @@ void php_stream_display_wrapper_errors(php_stream_wrapper *wrapper, void php_stream_tidy_wrapper_error_log(php_stream_wrapper *wrapper) { if (wrapper && FG(wrapper_logged_errors)) { - zend_hash_str_del(FG(wrapper_logged_errors), (const char *) &wrapper, sizeof(wrapper)); + const char *wrapper_name = wrapper ? wrapper->wops->label : "unknown"; + zend_hash_str_del(FG(wrapper_logged_errors), wrapper_name, strlen(wrapper_name)); } } From e2555ab6b966197b18a811678b021c2ea535d78d Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Tue, 18 Nov 2025 11:36:40 +0100 Subject: [PATCH 27/68] stream: stream remove not reported warning --- ext/standard/php_fopen_wrapper.c | 3 +-- ext/standard/tests/file/php_fd_wrapper_03.phpt | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/ext/standard/php_fopen_wrapper.c b/ext/standard/php_fopen_wrapper.c index b13f18e08bf78..902b0f853f4e4 100644 --- a/ext/standard/php_fopen_wrapper.c +++ b/ext/standard/php_fopen_wrapper.c @@ -396,8 +396,7 @@ static php_stream * php_stream_url_wrap_php(php_stream_wrapper *wrapper, const c } else { /* invalid php://thingy */ php_stream_wrapper_warn(wrapper, context, options, - STREAM_ERROR_CODE_INVALID_URL, - "Invalid php:// URL specified"); + STREAM_ERROR_CODE_INVALID_URL, "Invalid php:// URL specified"); return NULL; } diff --git a/ext/standard/tests/file/php_fd_wrapper_03.phpt b/ext/standard/tests/file/php_fd_wrapper_03.phpt index 991c497f5e193..a19d1f5acd94b 100644 --- a/ext/standard/tests/file/php_fd_wrapper_03.phpt +++ b/ext/standard/tests/file/php_fd_wrapper_03.phpt @@ -10,7 +10,6 @@ fopen("php://fd/1/", "w"); echo "\nDone.\n"; ?> --EXPECTF-- -Warning: fopen(): Invalid php:// URL specified in %s on line %d Warning: fopen(php://fd): Failed to open stream: operation failed in %s on line 2 From 18d55d696ca9a57a585ef2f481a9338d887a0707 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Tue, 18 Nov 2025 12:06:34 +0100 Subject: [PATCH 28/68] stream: fix reporting errors in rename --- ext/standard/file.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/standard/file.c b/ext/standard/file.c index 364985f786b7e..3b0112a0aad15 100644 --- a/ext/standard/file.c +++ b/ext/standard/file.c @@ -1222,7 +1222,7 @@ PHP_FUNCTION(rename) context = php_stream_context_from_zval(zcontext, 0); - RETURN_BOOL(wrapper->wops->rename(wrapper, old_name, new_name, 0, context)); + RETURN_BOOL(wrapper->wops->rename(wrapper, old_name, new_name, REPORT_ERRORS, context)); } /* }}} */ From 937941d284e2ab2ba9ce00ead3b3cbc5a3d1e032 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Tue, 18 Nov 2025 12:46:38 +0100 Subject: [PATCH 29/68] stream: do not store wrapper errors if no REPORT_ERRORS set --- main/streams/stream_errors.c | 65 +++++++++++++++++++----------------- 1 file changed, 35 insertions(+), 30 deletions(-) diff --git a/main/streams/stream_errors.c b/main/streams/stream_errors.c index 6fad781750d2a..cdf3775ed277d 100644 --- a/main/streams/stream_errors.c +++ b/main/streams/stream_errors.c @@ -286,10 +286,8 @@ static void php_stream_wrapper_error_internal_with_name(const char *wrapper_name { zend_string *message = vstrpprintf(0, fmt, args); - if (options & REPORT_ERRORS) { - php_stream_process_error(context, wrapper_name, NULL, docref, code, ZSTR_VAL(message), - param, severity, terminal); - } + php_stream_process_error(context, wrapper_name, NULL, docref, code, ZSTR_VAL(message), + param, severity, terminal); php_stream_store_error_common( context, NULL, message, docref, code, wrapper_name, param, severity, terminal); @@ -311,48 +309,56 @@ PHPAPI void php_stream_wrapper_error_with_name(const char *wrapper_name, php_stream_context *context, const char *docref, int options, int severity, bool terminal, int code, const char *fmt, ...) { - va_list args; - va_start(args, fmt); - php_stream_wrapper_error_internal_with_name( - wrapper_name, context, docref, options, severity, terminal, code, NULL, fmt, args); - va_end(args); + if (options & REPORT_ERRORS) { + va_list args; + va_start(args, fmt); + php_stream_wrapper_error_internal_with_name( + wrapper_name, context, docref, options, severity, terminal, code, NULL, fmt, args); + va_end(args); + } } PHPAPI void php_stream_wrapper_error(php_stream_wrapper *wrapper, php_stream_context *context, const char *docref, int options, int severity, bool terminal, int code, const char *fmt, ...) { - va_list args; - va_start(args, fmt); - php_stream_wrapper_error_internal( - wrapper, context, docref, options, severity, terminal, code, NULL, fmt, args); - va_end(args); + if (options & REPORT_ERRORS) { + va_list args; + va_start(args, fmt); + php_stream_wrapper_error_internal( + wrapper, context, docref, options, severity, terminal, code, NULL, fmt, args); + va_end(args); + } } PHPAPI void php_stream_wrapper_error_param(php_stream_wrapper *wrapper, php_stream_context *context, const char *docref, int options, int severity, bool terminal, int code, const char *param, const char *fmt, ...) { - va_list args; - va_start(args, fmt); - char *param_copy = param ? estrdup(param): NULL; - php_stream_wrapper_error_internal( - wrapper, context, docref, options, severity, terminal, code, param_copy, fmt, args); - va_end(args); + if (options & REPORT_ERRORS) { + va_list args; + va_start(args, fmt); + char *param_copy = param ? estrdup(param): NULL; + php_stream_wrapper_error_internal( + wrapper, context, docref, options, severity, terminal, code, param_copy, fmt, args); + va_end(args); + } } PHPAPI void php_stream_wrapper_error_param2(php_stream_wrapper *wrapper, php_stream_context *context, const char *docref, int options, int severity, bool terminal, int code, const char *param1, const char *param2, const char *fmt, ...) { - char *combined_param; - spprintf(&combined_param, 0, "%s,%s", param1, param2); - - va_list args; - va_start(args, fmt); - php_stream_wrapper_error_internal( - wrapper, context, docref, options, severity, terminal, code, combined_param, fmt, args); - va_end(args); + if (options & REPORT_ERRORS) { + char *combined_param; + spprintf(&combined_param, 0, "%s,%s", param1, param2); + + va_list args; + va_start(args, fmt); + php_stream_wrapper_error_internal( + wrapper, context, docref, options, severity, terminal, code, combined_param, fmt, args); + va_end(args); + } } /* Wrapper error logging - stores in FG(wrapper_logged_errors) */ @@ -394,13 +400,12 @@ static void php_stream_wrapper_log_error_internal(const php_stream_wrapper *wrap /* Report immediately using standard error functions */ php_stream_wrapper_error_internal_with_name( wrapper_name, context, NULL, options, severity, terminal, code, param, fmt, args); - zend_string_release(message); } else { /* Store for later display in FG(wrapper_logged_errors) */ php_stream_wrapper_log_store_error( message, code, wrapper_name, param, severity, terminal); - zend_string_release(message); } + zend_string_release(message); } PHPAPI void php_stream_wrapper_log_error(const php_stream_wrapper *wrapper, From af6a5364742f4ff6a6e304184eb3cf70a291f503 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Tue, 18 Nov 2025 14:41:06 +0100 Subject: [PATCH 30/68] stream: add stream_get_errors function --- ext/standard/basic_functions.stub.php | 6 ++ ext/standard/basic_functions_arginfo.h | 8 ++- ext/standard/basic_functions_decl.h | 8 +-- ext/standard/streamsfuncs.c | 98 ++++++++++++++++++++++++++ 4 files changed, 115 insertions(+), 5 deletions(-) diff --git a/ext/standard/basic_functions.stub.php b/ext/standard/basic_functions.stub.php index 6d0c565fc2d41..54e69905038fc 100644 --- a/ext/standard/basic_functions.stub.php +++ b/ext/standard/basic_functions.stub.php @@ -3549,6 +3549,12 @@ function stream_resolve_include_path(string $filename): string|false {} */ function stream_get_wrappers(): array {} +/** + * @param resource|string|null $subject + * @return array + */ +function stream_get_errors($subject = null): array {} + /** * @return array * @refcount 1 diff --git a/ext/standard/basic_functions_arginfo.h b/ext/standard/basic_functions_arginfo.h index d0109fa27c960..1e9c88fd21b0a 100644 --- a/ext/standard/basic_functions_arginfo.h +++ b/ext/standard/basic_functions_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit basic_functions.stub.php instead. - * Stub hash: f5583557f058e4862750d1262296d7f59cb0eed0 + * Stub hash: a4b0db912b5cd5b7d36925da9f5d1cf9d6e19ba4 * Has decl header: yes */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_set_time_limit, 0, 1, _IS_BOOL, 0) @@ -1987,6 +1987,10 @@ ZEND_END_ARG_INFO() #define arginfo_stream_get_wrappers arginfo_ob_list_handlers +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_stream_get_errors, 0, 0, IS_ARRAY, 0) + ZEND_ARG_INFO_WITH_DEFAULT_VALUE(0, subject, "null") +ZEND_END_ARG_INFO() + #define arginfo_stream_get_transports arginfo_ob_list_handlers #define arginfo_stream_is_local arginfo_rewind @@ -2829,6 +2833,7 @@ ZEND_FUNCTION(stream_get_meta_data); ZEND_FUNCTION(stream_get_line); ZEND_FUNCTION(stream_resolve_include_path); ZEND_FUNCTION(stream_get_wrappers); +ZEND_FUNCTION(stream_get_errors); ZEND_FUNCTION(stream_get_transports); ZEND_FUNCTION(stream_is_local); ZEND_FUNCTION(stream_isatty); @@ -3437,6 +3442,7 @@ static const zend_function_entry ext_functions[] = { ZEND_FE(stream_get_line, arginfo_stream_get_line) ZEND_FE(stream_resolve_include_path, arginfo_stream_resolve_include_path) ZEND_FE(stream_get_wrappers, arginfo_stream_get_wrappers) + ZEND_FE(stream_get_errors, arginfo_stream_get_errors) ZEND_FE(stream_get_transports, arginfo_stream_get_transports) ZEND_FE(stream_is_local, arginfo_stream_is_local) ZEND_FE(stream_isatty, arginfo_stream_isatty) diff --git a/ext/standard/basic_functions_decl.h b/ext/standard/basic_functions_decl.h index 139b47f2444d4..c44ef56182fa6 100644 --- a/ext/standard/basic_functions_decl.h +++ b/ext/standard/basic_functions_decl.h @@ -1,8 +1,8 @@ /* This is a generated file, edit basic_functions.stub.php instead. - * Stub hash: f5583557f058e4862750d1262296d7f59cb0eed0 */ + * Stub hash: a4b0db912b5cd5b7d36925da9f5d1cf9d6e19ba4 */ -#ifndef ZEND_BASIC_FUNCTIONS_DECL_f5583557f058e4862750d1262296d7f59cb0eed0_H -#define ZEND_BASIC_FUNCTIONS_DECL_f5583557f058e4862750d1262296d7f59cb0eed0_H +#ifndef ZEND_BASIC_FUNCTIONS_DECL_a4b0db912b5cd5b7d36925da9f5d1cf9d6e19ba4_H +#define ZEND_BASIC_FUNCTIONS_DECL_a4b0db912b5cd5b7d36925da9f5d1cf9d6e19ba4_H typedef enum zend_enum_RoundingMode { ZEND_ENUM_RoundingMode_HalfAwayFromZero = 1, @@ -15,4 +15,4 @@ typedef enum zend_enum_RoundingMode { ZEND_ENUM_RoundingMode_PositiveInfinity = 8, } zend_enum_RoundingMode; -#endif /* ZEND_BASIC_FUNCTIONS_DECL_f5583557f058e4862750d1262296d7f59cb0eed0_H */ +#endif /* ZEND_BASIC_FUNCTIONS_DECL_a4b0db912b5cd5b7d36925da9f5d1cf9d6e19ba4_H */ diff --git a/ext/standard/streamsfuncs.c b/ext/standard/streamsfuncs.c index 506ce0dafed8b..6472bbc23dedc 100644 --- a/ext/standard/streamsfuncs.c +++ b/ext/standard/streamsfuncs.c @@ -594,6 +594,104 @@ PHP_FUNCTION(stream_get_wrappers) } /* }}} */ +/* Helper function to convert error list to array */ +static void php_stream_errors_list_to_array(zend_llist *list, zval *return_value) +{ + php_stream_error_entry **err_entry_p; + zend_llist_position pos; + + for (err_entry_p = zend_llist_get_first_ex(list, &pos); + err_entry_p; + err_entry_p = zend_llist_get_next_ex(list, &pos)) { + php_stream_error_entry *entry = *err_entry_p; + zval error_array; + array_init(&error_array); + + add_assoc_str(&error_array, "message", zend_string_copy(entry->message)); + add_assoc_long(&error_array, "code", entry->code); + add_assoc_long(&error_array, "severity", entry->severity); + add_assoc_bool(&error_array, "terminal", entry->terminal); + + if (entry->wrapper_name) { + add_assoc_string(&error_array, "wrapper", entry->wrapper_name); + } + if (entry->param) { + add_assoc_string(&error_array, "param", entry->param); + } + if (entry->docref) { + add_assoc_string(&error_array, "docref", entry->docref); + } + + add_next_index_zval(return_value, &error_array); + } +} + +/* Retrieves list of stored stream errors */ +PHP_FUNCTION(stream_get_errors) +{ + zval *subject = NULL; + php_stream *stream = NULL; + char *wrapper_name = NULL; + size_t wrapper_name_len = 0; + bool get_all_wrappers = false; + + ZEND_PARSE_PARAMETERS_START(0, 1) + Z_PARAM_OPTIONAL + Z_PARAM_ZVAL(subject) + ZEND_PARSE_PARAMETERS_END(); + + /* Determine what we're querying for */ + if (subject == NULL) { + /* No parameter - get all wrapper errors */ + get_all_wrappers = true; + } else if (Z_TYPE_P(subject) == IS_RESOURCE) { + /* Stream resource - get errors for this stream */ + php_stream_from_zval_no_verify(stream, subject); + if (stream == NULL) { + zend_argument_type_error(1, "must be a valid stream resource"); + RETURN_THROWS(); + } + } else if (Z_TYPE_P(subject) == IS_STRING) { + /* Wrapper name - get errors for this wrapper */ + wrapper_name = Z_STRVAL_P(subject); + wrapper_name_len = Z_STRLEN_P(subject); + } else { + zend_argument_type_error(1, "must be a stream resource, string, or null"); + RETURN_THROWS(); + } + + array_init(return_value); + + /* Handle stream errors */ + if (stream) { + if (stream->error_list) { + php_stream_errors_list_to_array(stream->error_list, return_value); + } + } else if (get_all_wrappers) { + /* Get errors from all wrappers */ + if (FG(wrapper_stored_errors)) { + zend_string *key; + zval *val; + ZEND_HASH_FOREACH_STR_KEY_VAL(FG(wrapper_stored_errors), key, val) { + if (key) { + zend_llist *list = (zend_llist *) Z_PTR_P(val); + php_stream_errors_list_to_array(list, return_value); + } + } ZEND_HASH_FOREACH_END(); + } + } else if (wrapper_name) { + /* Get errors for specific wrapper */ + if (FG(wrapper_stored_errors)) { + zend_llist *list = zend_hash_str_find_ptr( + FG(wrapper_stored_errors), wrapper_name, wrapper_name_len); + + if (list) { + php_stream_errors_list_to_array(list, return_value); + } + } + } +} + /* {{{ stream_select related functions */ static int stream_array_to_fd_set(const HashTable *stream_array, fd_set *fds, php_socket_t *max_fd) { From e88385a47c2443b0fc445e5fe98b1c4ab4bbafbf Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Tue, 18 Nov 2025 18:31:18 +0100 Subject: [PATCH 31/68] stream: fix error storing for persistent streams --- main/streams/php_stream_errors.h | 1 + main/streams/stream_errors.c | 39 ++++++++++++++++++++------------ 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/main/streams/php_stream_errors.h b/main/streams/php_stream_errors.h index 9a926c952c520..d53e9a0a5fe1e 100644 --- a/main/streams/php_stream_errors.h +++ b/main/streams/php_stream_errors.h @@ -133,6 +133,7 @@ typedef struct { char *param; int severity; bool terminal; + bool persistent; } php_stream_error_entry; /* Main error reporting functions */ diff --git a/main/streams/stream_errors.c b/main/streams/stream_errors.c index cdf3775ed277d..03e989a1395ca 100644 --- a/main/streams/stream_errors.c +++ b/main/streams/stream_errors.c @@ -29,10 +29,12 @@ static void php_stream_error_entry_dtor(void *error) { php_stream_error_entry *entry = *(php_stream_error_entry **) error; zend_string_release(entry->message); - efree(entry->wrapper_name); - efree(entry->docref); + pefree(entry->wrapper_name, entry->persistent); + pefree(entry->docref, entry->persistent); + // param is not currently supported for streams so cannot be persistent + ZEND_ASSERT(!entry->persistent || entry->param == NULL); efree(entry->param); - efree(entry); + pefree(entry, entry->persistent); } static void php_stream_error_list_dtor(zval *item) @@ -215,18 +217,23 @@ static void php_stream_process_error(php_stream_context *context, const char *wr /* Helper to create error entry */ static php_stream_error_entry *php_stream_create_error_entry(zend_string *message, int code, const char *wrapper_name, const char *docref, char *param, int severity, - bool terminal) + bool terminal, bool persistent) { - php_stream_error_entry *entry = emalloc(sizeof(php_stream_error_entry)); + if (persistent) { + message = zend_string_dup(message, true); + } else { + zend_string_addref(message); + } + + php_stream_error_entry *entry = pemalloc(sizeof(php_stream_error_entry), persistent); entry->message = message; entry->code = code; - entry->wrapper_name = wrapper_name ? estrdup(wrapper_name) : NULL; - entry->docref = docref ? estrdup(docref) : NULL; + entry->wrapper_name = wrapper_name ? pestrdup(wrapper_name, persistent) : NULL; + entry->docref = docref ? pestrdup(docref, persistent) : NULL; entry->param = param; entry->severity = severity; entry->terminal = terminal; - - zend_string_addref(message); + entry->persistent = persistent; return entry; } @@ -243,17 +250,16 @@ static void php_stream_store_error_common(php_stream_context *context, php_strea efree(param); return; } - php_stream_error_entry *entry = php_stream_create_error_entry( - message, code, wrapper_name, docref, param, severity, terminal); zend_llist *list; - + bool persistent = false; if (stream) { + persistent = stream->is_persistent; /* Store in stream's error list */ if (!stream->error_list) { - stream->error_list = emalloc(sizeof(zend_llist)); + stream->error_list = pemalloc(sizeof(zend_llist), persistent); zend_llist_init(stream->error_list, sizeof(php_stream_error_entry *), - php_stream_error_entry_dtor, 0); + php_stream_error_entry_dtor, persistent); } list = stream->error_list; } else { @@ -276,6 +282,9 @@ static void php_stream_store_error_common(php_stream_context *context, php_strea } } + php_stream_error_entry *entry = php_stream_create_error_entry( + message, code, wrapper_name, docref, param, severity, terminal, persistent); + zend_llist_add_element(list, &entry); } @@ -368,7 +377,7 @@ static void php_stream_wrapper_log_store_error(zend_string *message, int code, { char *param_copy = param ? estrdup(param): NULL; php_stream_error_entry *entry = php_stream_create_error_entry( - message, code, wrapper_name, NULL, param_copy, severity, terminal); + message, code, wrapper_name, NULL, param_copy, severity, terminal, false); if (!FG(wrapper_logged_errors)) { ALLOC_HASHTABLE(FG(wrapper_logged_errors)); From 68a33bd1c9a982d0e690a805cdf00cacd60de00b Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Tue, 18 Nov 2025 18:31:59 +0100 Subject: [PATCH 32/68] stream: add missing error mode and store constants --- main/streams/stream_errors.stub.php | 42 ++++++++++++++++++++++++++++ main/streams/stream_errors_arginfo.h | 10 ++++++- 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/main/streams/stream_errors.stub.php b/main/streams/stream_errors.stub.php index 8a27e0060fc3d..fb6c5584a5f48 100644 --- a/main/streams/stream_errors.stub.php +++ b/main/streams/stream_errors.stub.php @@ -11,6 +11,48 @@ public function getParam(): ?string {} public function getWrapperName(): string {} } +/** + * @var int + * @cvalue PHP_STREAM_ERROR_MODE_ERROR + */ +const STREAM_ERROR_MODE_ERROR = UNKNOWN; +/** + * @var int + * @cvalue PHP_STREAM_ERROR_MODE_EXCEPTION + */ +const STREAM_ERROR_MODE_EXCEPTION = UNKNOWN; +/** + * @var int + * @cvalue PHP_STREAM_ERROR_MODE_SILENT + */ +const STREAM_ERROR_MODE_SILENT = UNKNOWN; + +/** + * @var int + * @cvalue PHP_STREAM_ERROR_STORE_AUTO + */ +const STREAM_ERROR_STORE_AUTO = UNKNOWN; +/** + * @var int + * @cvalue PHP_STREAM_ERROR_STORE_NONE + */ +const STREAM_ERROR_STORE_NONE = UNKNOWN; +/** + * @var int + * @cvalue PHP_STREAM_ERROR_STORE_NON_TERM + */ +const STREAM_ERROR_STORE_NON_TERMINAL = UNKNOWN; +/** + * @var int + * @cvalue PHP_STREAM_ERROR_STORE_TERMINAL + */ +const STREAM_ERROR_STORE_TERMINAL = UNKNOWN; +/** + * @var int + * @cvalue PHP_STREAM_ERROR_STORE_ALL + */ +const STREAM_ERROR_STORE_ALL = UNKNOWN; + /** * @var int * @cvalue STREAM_ERROR_CODE_NONE diff --git a/main/streams/stream_errors_arginfo.h b/main/streams/stream_errors_arginfo.h index 523cf64323a0e..79d86059dbdb6 100644 --- a/main/streams/stream_errors_arginfo.h +++ b/main/streams/stream_errors_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: faa3f0e64b8388a495ac645fd3eda49c1ed243bd */ + * Stub hash: 97a63d009e4a3e951b0c3b213e9cb784d1af5634 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_StreamException_getParam, 0, 0, IS_STRING, 1) ZEND_END_ARG_INFO() @@ -18,6 +18,14 @@ static const zend_function_entry class_StreamException_methods[] = { static void register_stream_errors_symbols(int module_number) { + REGISTER_LONG_CONSTANT("STREAM_ERROR_MODE_ERROR", PHP_STREAM_ERROR_MODE_ERROR, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("STREAM_ERROR_MODE_EXCEPTION", PHP_STREAM_ERROR_MODE_EXCEPTION, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("STREAM_ERROR_MODE_SILENT", PHP_STREAM_ERROR_MODE_SILENT, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("STREAM_ERROR_STORE_AUTO", PHP_STREAM_ERROR_STORE_AUTO, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("STREAM_ERROR_STORE_NONE", PHP_STREAM_ERROR_STORE_NONE, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("STREAM_ERROR_STORE_NON_TERMINAL", PHP_STREAM_ERROR_STORE_NON_TERM, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("STREAM_ERROR_STORE_TERMINAL", PHP_STREAM_ERROR_STORE_TERMINAL, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("STREAM_ERROR_STORE_ALL", PHP_STREAM_ERROR_STORE_ALL, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_NONE", STREAM_ERROR_CODE_NONE, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_GENERIC", STREAM_ERROR_CODE_GENERIC, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_READ_FAILED", STREAM_ERROR_CODE_READ_FAILED, CONST_PERSISTENT); From 91974e58ba651c52a8469daba32456d1a54b7d36 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Tue, 18 Nov 2025 18:34:18 +0100 Subject: [PATCH 33/68] stream: set context for opened streams This is limited to non persistent streams to be safe. If it shows problematic for BC reasons, it should be limited to only some context (e.g. if error options set). --- main/streams/streams.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/main/streams/streams.c b/main/streams/streams.c index 49154daabea4f..858157f79f810 100644 --- a/main/streams/streams.c +++ b/main/streams/streams.c @@ -2186,6 +2186,9 @@ PHPAPI php_stream *_php_stream_open_wrapper_ex(const char *path, const char *mod stream->open_filename = __zend_orig_filename ? __zend_orig_filename : __zend_filename; stream->open_lineno = __zend_orig_lineno ? __zend_orig_lineno : __zend_lineno; #endif + if (stream->ctx == NULL && context != NULL && !persistent) { + php_stream_context_set(stream, context); + } } if (stream != NULL && (options & STREAM_MUST_SEEK)) { From 46f99930e3911f87e15f59da346c969f7475372b Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Tue, 18 Nov 2025 18:36:20 +0100 Subject: [PATCH 34/68] stream: fix leaked stream error list --- main/streams/streams.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/main/streams/streams.c b/main/streams/streams.c index 858157f79f810..3bb9260b968ca 100644 --- a/main/streams/streams.c +++ b/main/streams/streams.c @@ -378,6 +378,11 @@ fprintf(stderr, "stream_free: %s:%p[%s] preserve_handle=%d release_cast=%d remov ZVAL_UNDEF(&stream->wrapperdata); } + if (stream->error_list) { + zend_llist_destroy(stream->error_list); + pefree(stream->error_list, stream->is_persistent); + } + if (stream->readbuf) { pefree(stream->readbuf, stream->is_persistent); stream->readbuf = NULL; From 1db1ab49c2f24c623dcad9e6c1b525e27440d557 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Tue, 18 Nov 2025 18:37:30 +0100 Subject: [PATCH 35/68] stream: add tests for new stream error handling --- ...stream_errors_exception_mode_terminal.phpt | 24 +++ .../stream_errors_mix_modes_storage.phpt | 194 ++++++++++++++++++ .../stream_errors_modes_with_auto_store.phpt | 49 +++++ .../stream_errors_silent_with_handler.phpt | 33 +++ .../stream_errors_silent_with_storage.phpt | 27 +++ .../stream_errors_silent_without_storage.phpt | 20 ++ .../streams/stream_errors_standard_error.phpt | 20 ++ 7 files changed, 367 insertions(+) create mode 100644 ext/standard/tests/streams/stream_errors_exception_mode_terminal.phpt create mode 100644 ext/standard/tests/streams/stream_errors_mix_modes_storage.phpt create mode 100644 ext/standard/tests/streams/stream_errors_modes_with_auto_store.phpt create mode 100644 ext/standard/tests/streams/stream_errors_silent_with_handler.phpt create mode 100644 ext/standard/tests/streams/stream_errors_silent_with_storage.phpt create mode 100644 ext/standard/tests/streams/stream_errors_silent_without_storage.phpt create mode 100644 ext/standard/tests/streams/stream_errors_standard_error.phpt diff --git a/ext/standard/tests/streams/stream_errors_exception_mode_terminal.phpt b/ext/standard/tests/streams/stream_errors_exception_mode_terminal.phpt new file mode 100644 index 0000000000000..016b989276fa0 --- /dev/null +++ b/ext/standard/tests/streams/stream_errors_exception_mode_terminal.phpt @@ -0,0 +1,24 @@ +--TEST-- +Stream errors - exception mode for terminal errors +--FILE-- + [ + 'error_mode' => STREAM_ERROR_MODE_EXCEPTION, + ] +]); + +try { + $stream = fopen('php://nonexistent', 'r', false, $context); +} catch (StreamException $e) { + echo "Caught: " . $e->getMessage() . "\n"; + echo "Code: " . $e->getCode() . "\n"; + echo "Wrapper: " . $e->getWrapperName() . "\n"; +} + +?> +--EXPECTF-- +Caught: Failed to open stream: operation failed +Code: 36 +Wrapper: PHP diff --git a/ext/standard/tests/streams/stream_errors_mix_modes_storage.phpt b/ext/standard/tests/streams/stream_errors_mix_modes_storage.phpt new file mode 100644 index 0000000000000..cb765de62fe07 --- /dev/null +++ b/ext/standard/tests/streams/stream_errors_mix_modes_storage.phpt @@ -0,0 +1,194 @@ +--TEST-- +Stream errors - silent mode with mixed error stores +--FILE-- +position += $count; + return str_repeat('x', $count + 10); + } + + public function stream_eof() { + return $this->position >= 100; + } + + public function stream_stat() { + return []; + } +} + +stream_wrapper_register('test', 'TestStream'); + +function stream_test_errors($title, $context) { + $stream = fopen('test://foo', 'r', false, $context); + try { + echo $title . "\n"; + $readin = fopen( 'php://stdin', 'r' ); + $data = fread( $stream, 10 ); + + $read = [$readin, $stream]; + $write = NULL; + $except = NULL; + stream_select($read, $write, $except, 0); + } catch (StreamException $e) { + echo 'EXCEPTION: ' . $e->getMessage() . "\n"; + } + + $errors = stream_get_errors($stream); + var_dump($errors); +} + +stream_test_errors('ALL', stream_context_create([ + 'stream' => [ + 'error_mode' => STREAM_ERROR_MODE_SILENT, + 'error_store' => STREAM_ERROR_STORE_ALL, + ] +])); +stream_test_errors('NON TERMINAL', stream_context_create([ + 'stream' => [ + 'error_mode' => STREAM_ERROR_MODE_SILENT, + 'error_store' => STREAM_ERROR_STORE_NON_TERMINAL, + ] +])); +stream_test_errors('TERMINAL', stream_context_create([ + 'stream' => [ + 'error_mode' => STREAM_ERROR_MODE_SILENT, + 'error_store' => STREAM_ERROR_STORE_TERMINAL, + ] +])); +stream_test_errors('AUTO EXCEPTION', stream_context_create([ + 'stream' => [ + 'error_mode' => STREAM_ERROR_MODE_EXCEPTION, + 'error_store' => STREAM_ERROR_STORE_AUTO, + ] +])); +stream_test_errors('AUTO ERROR', stream_context_create([ + 'stream' => [ + 'error_mode' => STREAM_ERROR_MODE_ERROR, + 'error_store' => STREAM_ERROR_STORE_AUTO, + ] +])); + +?> +--EXPECTF-- +ALL +array(3) { + [0]=> + array(5) { + ["message"]=> + string(113) "TestStream::stream_read - read 10 bytes more data than requested (8202 read, 8192 max) - excess data will be lost" + ["code"]=> + int(161) + ["severity"]=> + int(2) + ["terminal"]=> + bool(false) + ["wrapper"]=> + string(10) "user-space" + } + [1]=> + array(5) { + ["message"]=> + string(43) "TestStream::stream_cast is not implemented!" + ["code"]=> + int(70) + ["severity"]=> + int(2) + ["terminal"]=> + bool(true) + ["wrapper"]=> + string(10) "user-space" + } + [2]=> + array(5) { + ["message"]=> + string(73) "Cannot represent a stream of type user-space as a select()able descriptor" + ["code"]=> + int(101) + ["severity"]=> + int(2) + ["terminal"]=> + bool(true) + ["wrapper"]=> + string(10) "user-space" + } +} +NON TERMINAL +array(1) { + [0]=> + array(5) { + ["message"]=> + string(113) "TestStream::stream_read - read 10 bytes more data than requested (8202 read, 8192 max) - excess data will be lost" + ["code"]=> + int(161) + ["severity"]=> + int(2) + ["terminal"]=> + bool(false) + ["wrapper"]=> + string(10) "user-space" + } +} +TERMINAL +array(2) { + [0]=> + array(5) { + ["message"]=> + string(43) "TestStream::stream_cast is not implemented!" + ["code"]=> + int(70) + ["severity"]=> + int(2) + ["terminal"]=> + bool(true) + ["wrapper"]=> + string(10) "user-space" + } + [1]=> + array(5) { + ["message"]=> + string(73) "Cannot represent a stream of type user-space as a select()able descriptor" + ["code"]=> + int(101) + ["severity"]=> + int(2) + ["terminal"]=> + bool(true) + ["wrapper"]=> + string(10) "user-space" + } +} +AUTO EXCEPTION +EXCEPTION: Cannot represent a stream of type user-space as a select()able descriptor +array(1) { + [0]=> + array(5) { + ["message"]=> + string(113) "TestStream::stream_read - read 10 bytes more data than requested (8202 read, 8192 max) - excess data will be lost" + ["code"]=> + int(161) + ["severity"]=> + int(2) + ["terminal"]=> + bool(false) + ["wrapper"]=> + string(10) "user-space" + } +} +AUTO ERROR + +Warning: fread(): TestStream::stream_read - read 10 bytes more data than requested (8202 read, 8192 max) - excess data will be lost in %s on line %d + +Warning: stream_select(): TestStream::stream_cast is not implemented! in %s on line %d + +Warning: stream_select(): Cannot represent a stream of type user-space as a select()able descriptor in %s on line %d +array(0) { +} diff --git a/ext/standard/tests/streams/stream_errors_modes_with_auto_store.phpt b/ext/standard/tests/streams/stream_errors_modes_with_auto_store.phpt new file mode 100644 index 0000000000000..bda445eabe428 --- /dev/null +++ b/ext/standard/tests/streams/stream_errors_modes_with_auto_store.phpt @@ -0,0 +1,49 @@ +--TEST-- +Stream errors - error_store AUTO mode behavior +--FILE-- + [ + 'error_mode' => STREAM_ERROR_MODE_ERROR, + 'error_store' => STREAM_ERROR_STORE_AUTO, + ] +]); + +@fopen('php://nonexistent', 'r', false, $context1); +$errors1 = stream_get_errors('PHP'); +echo "ERROR mode AUTO: " . count($errors1) . "\n"; + +// AUTO with EXCEPTION mode should store NON_TERM +$context2 = stream_context_create([ + 'stream' => [ + 'error_mode' => STREAM_ERROR_MODE_EXCEPTION, + 'error_store' => STREAM_ERROR_STORE_AUTO, + ] +]); + +try { + fopen('php://nonexistent2', 'r', false, $context2); +} catch (StreamException $e) {} + +$errors2 = stream_get_errors('PHP'); +echo "EXCEPTION mode AUTO: " . count($errors2) . "\n"; + +// AUTO with SILENT mode should store ALL +$context3 = stream_context_create([ + 'stream' => [ + 'error_mode' => STREAM_ERROR_MODE_SILENT, + 'error_store' => STREAM_ERROR_STORE_AUTO, + ] +]); + +fopen('php://nonexistent3', 'r', false, $context3); +$errors3 = stream_get_errors('PHP'); +echo "SILENT mode AUTO: " . count($errors3) . "\n"; + +?> +--EXPECTF-- +ERROR mode AUTO: 0 +EXCEPTION mode AUTO: %d +SILENT mode AUTO: %d diff --git a/ext/standard/tests/streams/stream_errors_silent_with_handler.phpt b/ext/standard/tests/streams/stream_errors_silent_with_handler.phpt new file mode 100644 index 0000000000000..9ce86adb09658 --- /dev/null +++ b/ext/standard/tests/streams/stream_errors_silent_with_handler.phpt @@ -0,0 +1,33 @@ +--TEST-- +Stream errors - custom error handler +--FILE-- + [ + 'error_mode' => STREAM_ERROR_MODE_SILENT, + 'error_handler' => function($wrapper, $stream, $code, $message, $param) use (&$handler_called) { + $handler_called = true; + echo "Handler called\n"; + echo "Wrapper: $wrapper\n"; + echo "Code: $code\n"; + echo "Message: $message\n"; + echo "Param: " . ($param ?? 'null') . "\n"; + } + ] +]); + +$stream = fopen('php://nonexistent', 'r', false, $context); + +var_dump($handler_called); + +?> +--EXPECT-- +Handler called +Wrapper: PHP +Code: 36 +Message: Failed to open stream: operation failed +Param: php://nonexistent +bool(true) diff --git a/ext/standard/tests/streams/stream_errors_silent_with_storage.phpt b/ext/standard/tests/streams/stream_errors_silent_with_storage.phpt new file mode 100644 index 0000000000000..563857d308fff --- /dev/null +++ b/ext/standard/tests/streams/stream_errors_silent_with_storage.phpt @@ -0,0 +1,27 @@ +--TEST-- +Stream errors - silent mode with error storage +--FILE-- + [ + 'error_mode' => STREAM_ERROR_MODE_SILENT, + ] +]); + +$stream = fopen('php://nonexistent', 'r', false, $context); +var_dump($stream); + +$errors = stream_get_errors(); +echo "Error count: " . count($errors) . "\n"; +if (count($errors) > 0) { + echo "First error code: " . $errors[0]['code'] . "\n"; + echo "First error wrapper: " . $errors[0]['wrapper'] . "\n"; +} + +?> +--EXPECT-- +bool(false) +Error count: 1 +First error code: 36 +First error wrapper: PHP diff --git a/ext/standard/tests/streams/stream_errors_silent_without_storage.phpt b/ext/standard/tests/streams/stream_errors_silent_without_storage.phpt new file mode 100644 index 0000000000000..6ed79378d8226 --- /dev/null +++ b/ext/standard/tests/streams/stream_errors_silent_without_storage.phpt @@ -0,0 +1,20 @@ +--TEST-- +Stream errors - error_store NONE option +--FILE-- + [ + 'error_mode' => STREAM_ERROR_MODE_SILENT, + 'error_store' => STREAM_ERROR_STORE_NONE, + ] +]); + +$stream = fopen('php://nonexistent', 'r', false, $context); + +$errors = stream_get_errors(); +echo "Error count: " . count($errors) . "\n"; + +?> +--EXPECT-- +Error count: 0 diff --git a/ext/standard/tests/streams/stream_errors_standard_error.phpt b/ext/standard/tests/streams/stream_errors_standard_error.phpt new file mode 100644 index 0000000000000..a9725f0b89b26 --- /dev/null +++ b/ext/standard/tests/streams/stream_errors_standard_error.phpt @@ -0,0 +1,20 @@ +--TEST-- +Stream errors - error mode with standard error reporting +--FILE-- + [ + 'error_mode' => STREAM_ERROR_MODE_ERROR, + ] +]); + +// This will trigger a warning +$stream = fopen('php://nonexistent', 'r', false, $context); + +var_dump($stream); + +?> +--EXPECTF-- +Warning: fopen(php://nonexistent): Failed to open stream: %s in %s on line %d +bool(false) From a05924e4602529daf2c1ac61cbb259b0faace1d6 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Tue, 18 Nov 2025 19:44:53 +0100 Subject: [PATCH 36/68] stream: update reflection class name test --- .../tests/ReflectionExtension_getClassNames_basic.phpt | 1 + 1 file changed, 1 insertion(+) diff --git a/ext/reflection/tests/ReflectionExtension_getClassNames_basic.phpt b/ext/reflection/tests/ReflectionExtension_getClassNames_basic.phpt index 47813255381e4..dc72254abc076 100644 --- a/ext/reflection/tests/ReflectionExtension_getClassNames_basic.phpt +++ b/ext/reflection/tests/ReflectionExtension_getClassNames_basic.phpt @@ -16,5 +16,6 @@ AssertionError Directory RoundingMode StreamBucket +StreamException __PHP_Incomplete_Class php_user_filter From 63b7b577f4acc27a8e30098d0897972df4d17862 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Wed, 19 Nov 2025 20:09:01 +0100 Subject: [PATCH 37/68] stream: fix possible use of wrapper after it is freed --- main/streams/php_stream_errors.h | 8 ++ main/streams/stream_errors.c | 163 ++++++++++++++++++------------- main/streams/streams.c | 9 +- 3 files changed, 108 insertions(+), 72 deletions(-) diff --git a/main/streams/php_stream_errors.h b/main/streams/php_stream_errors.h index d53e9a0a5fe1e..b59083e234591 100644 --- a/main/streams/php_stream_errors.h +++ b/main/streams/php_stream_errors.h @@ -124,6 +124,9 @@ BEGIN_EXTERN_C() #define STREAM_ERROR_CODE_USERSPACE_INVALID_RETURN 161 #define STREAM_ERROR_CODE_USERSPACE_CALL_FAILED 162 +/* Wrapper name for PHP errors */ +#define PHP_STREAM_ERROR_WRAPPER_NAME(_wrapper) (_wrapper ? _wrapper->wops->label : "unknown") + /* Stored error entry */ typedef struct { zend_string *message; @@ -166,9 +169,14 @@ PHPAPI void php_stream_wrapper_log_error_param(const php_stream_wrapper *wrapper php_stream_context *context, int options, int severity, bool terminal, int code, const char *param, const char *fmt, ...) ZEND_ATTRIBUTE_FORMAT(printf, 8, 9); +PHPAPI void php_stream_display_wrapper_name_errors(const char *wrapper_name, + php_stream_context *context, int code, const char *path, const char *caption); + PHPAPI void php_stream_display_wrapper_errors(php_stream_wrapper *wrapper, php_stream_context *context, int code, const char *path, const char *caption); +PHPAPI void php_stream_tidy_wrapper_name_error_log(const char *wrapper_name); + PHPAPI void php_stream_tidy_wrapper_error_log(php_stream_wrapper *wrapper); /* Convenience macros */ diff --git a/main/streams/stream_errors.c b/main/streams/stream_errors.c index 03e989a1395ca..3228b3c5c8ed8 100644 --- a/main/streams/stream_errors.c +++ b/main/streams/stream_errors.c @@ -31,7 +31,7 @@ static void php_stream_error_entry_dtor(void *error) zend_string_release(entry->message); pefree(entry->wrapper_name, entry->persistent); pefree(entry->docref, entry->persistent); - // param is not currently supported for streams so cannot be persistent + // param is not currently supported for streams so cannot be persistent ZEND_ASSERT(!entry->persistent || entry->param == NULL); efree(entry->param); pefree(entry, entry->persistent); @@ -216,8 +216,8 @@ static void php_stream_process_error(php_stream_context *context, const char *wr /* Helper to create error entry */ static php_stream_error_entry *php_stream_create_error_entry(zend_string *message, int code, - const char *wrapper_name, const char *docref, char *param, int severity, - bool terminal, bool persistent) + const char *wrapper_name, const char *docref, char *param, int severity, bool terminal, + bool persistent) { if (persistent) { message = zend_string_dup(message, true); @@ -240,8 +240,8 @@ static php_stream_error_entry *php_stream_create_error_entry(zend_string *messag /* Common storage function*/ static void php_stream_store_error_common(php_stream_context *context, php_stream *stream, - zend_string *message, const char *docref, int code, - const char *wrapper_name, char *param, int severity, bool terminal) + zend_string *message, const char *docref, int code, const char *wrapper_name, char *param, + int severity, bool terminal) { int error_mode = php_stream_get_error_mode(context); int store_mode = php_stream_get_error_store_mode(context, error_mode); @@ -295,8 +295,8 @@ static void php_stream_wrapper_error_internal_with_name(const char *wrapper_name { zend_string *message = vstrpprintf(0, fmt, args); - php_stream_process_error(context, wrapper_name, NULL, docref, code, ZSTR_VAL(message), - param, severity, terminal); + php_stream_process_error(context, wrapper_name, NULL, docref, code, ZSTR_VAL(message), param, + severity, terminal); php_stream_store_error_common( context, NULL, message, docref, code, wrapper_name, param, severity, terminal); @@ -304,14 +304,27 @@ static void php_stream_wrapper_error_internal_with_name(const char *wrapper_name zend_string_release(message); } +static void php_stream_wrapper_error_internal_with_name_variadic(const char *wrapper_name, + php_stream_context *context, const char *docref, int options, int severity, bool terminal, + int code, char *param, const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + + php_stream_wrapper_error_internal_with_name( + wrapper_name, context, docref, options, severity, terminal, code, param, fmt, args); + + va_end(args); +} + static void php_stream_wrapper_error_internal(php_stream_wrapper *wrapper, php_stream_context *context, const char *docref, int options, int severity, bool terminal, int code, char *param, const char *fmt, va_list args) { - const char *wrapper_name = wrapper ? wrapper->wops->label : "unknown"; + const char *wrapper_name = PHP_STREAM_ERROR_WRAPPER_NAME(wrapper); - php_stream_wrapper_error_internal_with_name(wrapper_name, context, docref, options, severity, - terminal, code, param, fmt, args); + php_stream_wrapper_error_internal_with_name( + wrapper_name, context, docref, options, severity, terminal, code, param, fmt, args); } PHPAPI void php_stream_wrapper_error_with_name(const char *wrapper_name, @@ -347,7 +360,7 @@ PHPAPI void php_stream_wrapper_error_param(php_stream_wrapper *wrapper, php_stre if (options & REPORT_ERRORS) { va_list args; va_start(args, fmt); - char *param_copy = param ? estrdup(param): NULL; + char *param_copy = param ? estrdup(param) : NULL; php_stream_wrapper_error_internal( wrapper, context, docref, options, severity, terminal, code, param_copy, fmt, args); va_end(args); @@ -364,8 +377,8 @@ PHPAPI void php_stream_wrapper_error_param2(php_stream_wrapper *wrapper, va_list args; va_start(args, fmt); - php_stream_wrapper_error_internal( - wrapper, context, docref, options, severity, terminal, code, combined_param, fmt, args); + php_stream_wrapper_error_internal(wrapper, context, docref, options, severity, terminal, + code, combined_param, fmt, args); va_end(args); } } @@ -375,7 +388,7 @@ PHPAPI void php_stream_wrapper_error_param2(php_stream_wrapper *wrapper, static void php_stream_wrapper_log_store_error(zend_string *message, int code, const char *wrapper_name, const char *param, int severity, bool terminal) { - char *param_copy = param ? estrdup(param): NULL; + char *param_copy = param ? estrdup(param) : NULL; php_stream_error_entry *entry = php_stream_create_error_entry( message, code, wrapper_name, NULL, param_copy, severity, terminal, false); @@ -384,8 +397,8 @@ static void php_stream_wrapper_log_store_error(zend_string *message, int code, zend_hash_init(FG(wrapper_logged_errors), 8, NULL, php_stream_error_list_dtor, 0); } - zend_llist *list = zend_hash_str_find_ptr( - FG(wrapper_logged_errors), wrapper_name, strlen(wrapper_name)); + zend_llist *list + = zend_hash_str_find_ptr(FG(wrapper_logged_errors), wrapper_name, strlen(wrapper_name)); if (!list) { zend_llist new_list; @@ -403,7 +416,7 @@ static void php_stream_wrapper_log_error_internal(const php_stream_wrapper *wrap char *param, const char *fmt, va_list args) { zend_string *message = vstrpprintf(0, fmt, args); - const char *wrapper_name = wrapper ? wrapper->wops->label : "unknown"; + const char *wrapper_name = PHP_STREAM_ERROR_WRAPPER_NAME(wrapper); if (options & REPORT_ERRORS) { /* Report immediately using standard error functions */ @@ -411,8 +424,7 @@ static void php_stream_wrapper_log_error_internal(const php_stream_wrapper *wrap wrapper_name, context, NULL, options, severity, terminal, code, param, fmt, args); } else { /* Store for later display in FG(wrapper_logged_errors) */ - php_stream_wrapper_log_store_error( - message, code, wrapper_name, param, severity, terminal); + php_stream_wrapper_log_store_error(message, code, wrapper_name, param, severity, terminal); } zend_string_release(message); } @@ -434,7 +446,7 @@ PHPAPI void php_stream_wrapper_log_error_param(const php_stream_wrapper *wrapper { va_list args; va_start(args, fmt); - char *param_copy = param ? estrdup(param): NULL; + char *param_copy = param ? estrdup(param) : NULL; php_stream_wrapper_log_error_internal( wrapper, context, options, severity, terminal, code, param_copy, fmt, args); va_end(args); @@ -450,7 +462,7 @@ static zend_llist *php_stream_get_wrapper_errors_list(const char *wrapper_name) } } -void php_stream_display_wrapper_errors(php_stream_wrapper *wrapper, +PHPAPI void php_stream_display_wrapper_name_errors(const char *wrapper_name, php_stream_context *context, int code, const char *path, const char *caption) { char *msg; @@ -462,73 +474,84 @@ void php_stream_display_wrapper_errors(php_stream_wrapper *wrapper, return; } - const char *wrapper_name = wrapper ? wrapper->wops->label : "unknown"; char *tmp = estrdup(path); - if (wrapper) { - zend_llist *err_list = php_stream_get_wrapper_errors_list(wrapper_name); - if (err_list) { - size_t l = 0; - int brlen; - int i; - int count = (int) zend_llist_count(err_list); - const char *br; - php_stream_error_entry **err_entry_p; - zend_llist_position pos; - - if (PG(html_errors)) { - brlen = 7; - br = "
\n"; - } else { - brlen = 1; - br = "\n"; - } + zend_llist *err_list = php_stream_get_wrapper_errors_list(wrapper_name); + if (err_list) { + size_t l = 0; + int brlen; + int i; + int count = (int) zend_llist_count(err_list); + const char *br; + php_stream_error_entry **err_entry_p; + zend_llist_position pos; + + if (PG(html_errors)) { + brlen = 7; + br = "
\n"; + } else { + brlen = 1; + br = "\n"; + } - for (err_entry_p = zend_llist_get_first_ex(err_list, &pos), i = 0; err_entry_p; - err_entry_p = zend_llist_get_next_ex(err_list, &pos), i++) { - l += ZSTR_LEN((*err_entry_p)->message); - if (i < count - 1) { - l += brlen; - } + for (err_entry_p = zend_llist_get_first_ex(err_list, &pos), i = 0; err_entry_p; + err_entry_p = zend_llist_get_next_ex(err_list, &pos), i++) { + l += ZSTR_LEN((*err_entry_p)->message); + if (i < count - 1) { + l += brlen; } - msg = emalloc(l + 1); - msg[0] = '\0'; - for (err_entry_p = zend_llist_get_first_ex(err_list, &pos), i = 0; err_entry_p; - err_entry_p = zend_llist_get_next_ex(err_list, &pos), i++) { - strcat(msg, ZSTR_VAL((*err_entry_p)->message)); - if (i < count - 1) { - strcat(msg, br); - } + } + msg = emalloc(l + 1); + msg[0] = '\0'; + for (err_entry_p = zend_llist_get_first_ex(err_list, &pos), i = 0; err_entry_p; + err_entry_p = zend_llist_get_next_ex(err_list, &pos), i++) { + strcat(msg, ZSTR_VAL((*err_entry_p)->message)); + if (i < count - 1) { + strcat(msg, br); } + } - free_msg = 1; + free_msg = 1; + } else { + if (!strcmp(wrapper_name, php_plain_files_wrapper.wops->label)) { + msg = php_socket_strerror_s(errno, errstr, sizeof(errstr)); } else { - if (wrapper == &php_plain_files_wrapper) { - msg = php_socket_strerror_s(errno, errstr, sizeof(errstr)); - } else { - msg = "operation failed"; - } + msg = "operation failed"; } - } else { - msg = "no suitable wrapper could be found"; } php_strip_url_passwd(tmp); - php_stream_wrapper_warn_param(wrapper, context, REPORT_ERRORS, code, tmp, - "%s: %s", caption, msg); - efree(tmp); + php_stream_wrapper_error_internal_with_name_variadic(wrapper_name, context, NULL, REPORT_ERRORS, + E_WARNING, true, code, tmp, "%s: %s", caption, msg); + if (free_msg) { efree(msg); } } -void php_stream_tidy_wrapper_error_log(php_stream_wrapper *wrapper) +PHPAPI void php_stream_display_wrapper_errors(php_stream_wrapper *wrapper, + php_stream_context *context, int code, const char *path, const char *caption) { - if (wrapper && FG(wrapper_logged_errors)) { - const char *wrapper_name = wrapper ? wrapper->wops->label : "unknown"; + if (wrapper) { + const char *wrapper_name = PHP_STREAM_ERROR_WRAPPER_NAME(wrapper); + php_stream_display_wrapper_errors(wrapper_name, context, code, path, caption); + } +} + +PHPAPI void php_stream_tidy_wrapper_name_error_log(const char *wrapper_name) +{ + if (FG(wrapper_logged_errors)) { zend_hash_str_del(FG(wrapper_logged_errors), wrapper_name, strlen(wrapper_name)); } } +PHPAPI void php_stream_tidy_wrapper_error_log(php_stream_wrapper *wrapper) +{ + if (wrapper) { + const char *wrapper_name = PHP_STREAM_ERROR_WRAPPER_NAME(wrapper); + php_stream_tidy_wrapper_name_error_log(wrapper_name); + } +} + /* Stream error reporting */ PHPAPI void php_stream_error(php_stream *stream, const char *docref, int severity, bool terminal, @@ -549,8 +572,8 @@ PHPAPI void php_stream_error(php_stream *stream, const char *docref, int severit severity, terminal); /* Store error */ - php_stream_store_error_common(context, stream, message, docref, code, wrapper_name, NULL, - severity, terminal); + php_stream_store_error_common( + context, stream, message, docref, code, wrapper_name, NULL, severity, terminal); zend_string_release(message); } diff --git a/main/streams/streams.c b/main/streams/streams.c index 3bb9260b968ca..328104aae9745 100644 --- a/main/streams/streams.c +++ b/main/streams/streams.c @@ -2152,6 +2152,8 @@ PHPAPI php_stream *_php_stream_open_wrapper_ex(const char *path, const char *mod return NULL; } + /* wrapper name needs to be stored as wrapper can be removed in opener (user stream) */ + char *wrapper_name = pestrdup(PHP_STREAM_ERROR_WRAPPER_NAME(wrapper), persistent); if (wrapper) { if (!wrapper->wops->stream_opener) { php_stream_wrapper_log_warn(wrapper, context, options & ~REPORT_ERRORS, @@ -2206,6 +2208,7 @@ PHPAPI php_stream *_php_stream_open_wrapper_ex(const char *path, const char *mod if (resolved_path) { zend_string_release_ex(resolved_path, 0); } + pefree(wrapper_name, persistent); return stream; case PHP_STREAM_RELEASED: if (newstream->orig_path) { @@ -2215,6 +2218,7 @@ PHPAPI php_stream *_php_stream_open_wrapper_ex(const char *path, const char *mod if (resolved_path) { zend_string_release_ex(resolved_path, 0); } + pefree(wrapper_name, persistent); return newstream; default: php_stream_close(stream); @@ -2242,14 +2246,15 @@ PHPAPI php_stream *_php_stream_open_wrapper_ex(const char *path, const char *mod } if (stream == NULL && (options & REPORT_ERRORS)) { - php_stream_display_wrapper_errors(wrapper, context, STREAM_ERROR_CODE_OPEN_FAILED, path, + php_stream_display_wrapper_name_errors(wrapper_name, context, STREAM_ERROR_CODE_OPEN_FAILED, path, "Failed to open stream"); if (opened_path && *opened_path) { zend_string_release_ex(*opened_path, 0); *opened_path = NULL; } } - php_stream_tidy_wrapper_error_log(wrapper); + php_stream_tidy_wrapper_name_error_log(wrapper_name); + pefree(wrapper_name, persistent); if (resolved_path) { zend_string_release_ex(resolved_path, 0); } From 5a53a98783f49176f9196663759b65d7c79e4293 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Wed, 19 Nov 2025 23:07:35 +0100 Subject: [PATCH 38/68] stream: fix double error message creation --- main/streams/stream_errors.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/main/streams/stream_errors.c b/main/streams/stream_errors.c index 3228b3c5c8ed8..e4762f7f12869 100644 --- a/main/streams/stream_errors.c +++ b/main/streams/stream_errors.c @@ -289,17 +289,25 @@ static void php_stream_store_error_common(php_stream_context *context, php_strea } /* Wrapper error reporting - stores in FG(wrapper_stored_errors) */ -static void php_stream_wrapper_error_internal_with_name(const char *wrapper_name, +static void php_stream_wrapper_error_internal_with_name_and_message(const char *wrapper_name, php_stream_context *context, const char *docref, int options, int severity, bool terminal, - int code, char *param, const char *fmt, va_list args) + int code, char *param, zend_string *message) { - zend_string *message = vstrpprintf(0, fmt, args); - php_stream_process_error(context, wrapper_name, NULL, docref, code, ZSTR_VAL(message), param, severity, terminal); php_stream_store_error_common( context, NULL, message, docref, code, wrapper_name, param, severity, terminal); +} + +static void php_stream_wrapper_error_internal_with_name(const char *wrapper_name, + php_stream_context *context, const char *docref, int options, int severity, bool terminal, + int code, char *param, const char *fmt, va_list args) +{ + zend_string *message = vstrpprintf(0, fmt, args); + + php_stream_wrapper_error_internal_with_name_and_message( + wrapper_name, context, docref, options, severity, terminal, code, param, message); zend_string_release(message); } @@ -420,8 +428,8 @@ static void php_stream_wrapper_log_error_internal(const php_stream_wrapper *wrap if (options & REPORT_ERRORS) { /* Report immediately using standard error functions */ - php_stream_wrapper_error_internal_with_name( - wrapper_name, context, NULL, options, severity, terminal, code, param, fmt, args); + php_stream_wrapper_error_internal_with_name_and_message( + wrapper_name, context, NULL, options, severity, terminal, code, param, message); } else { /* Store for later display in FG(wrapper_logged_errors) */ php_stream_wrapper_log_store_error(message, code, wrapper_name, param, severity, terminal); @@ -533,7 +541,7 @@ PHPAPI void php_stream_display_wrapper_errors(php_stream_wrapper *wrapper, { if (wrapper) { const char *wrapper_name = PHP_STREAM_ERROR_WRAPPER_NAME(wrapper); - php_stream_display_wrapper_errors(wrapper_name, context, code, path, caption); + php_stream_display_wrapper_name_errors(wrapper_name, context, code, path, caption); } } From 9b3a5d6004a02185d90f67904b9ce79b24718eba Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Wed, 19 Nov 2025 23:31:31 +0100 Subject: [PATCH 39/68] stream: fix empty wrapper check in error displaying --- main/streams/php_stream_errors.h | 4 +- main/streams/stream_errors.c | 76 +++++++++++++++++--------------- 2 files changed, 43 insertions(+), 37 deletions(-) diff --git a/main/streams/php_stream_errors.h b/main/streams/php_stream_errors.h index b59083e234591..a519149285e66 100644 --- a/main/streams/php_stream_errors.h +++ b/main/streams/php_stream_errors.h @@ -125,7 +125,9 @@ BEGIN_EXTERN_C() #define STREAM_ERROR_CODE_USERSPACE_CALL_FAILED 162 /* Wrapper name for PHP errors */ -#define PHP_STREAM_ERROR_WRAPPER_NAME(_wrapper) (_wrapper ? _wrapper->wops->label : "unknown") +#define PHP_STREAM_ERROR_WRAPPER_DEFAULT_NAME ":na" +#define PHP_STREAM_ERROR_WRAPPER_NAME(_wrapper) \ + (_wrapper ? _wrapper->wops->label : PHP_STREAM_ERROR_WRAPPER_DEFAULT_NAME) /* Stored error entry */ typedef struct { diff --git a/main/streams/stream_errors.c b/main/streams/stream_errors.c index e4762f7f12869..0a199589370ae 100644 --- a/main/streams/stream_errors.c +++ b/main/streams/stream_errors.c @@ -483,48 +483,52 @@ PHPAPI void php_stream_display_wrapper_name_errors(const char *wrapper_name, } char *tmp = estrdup(path); - zend_llist *err_list = php_stream_get_wrapper_errors_list(wrapper_name); - if (err_list) { - size_t l = 0; - int brlen; - int i; - int count = (int) zend_llist_count(err_list); - const char *br; - php_stream_error_entry **err_entry_p; - zend_llist_position pos; - - if (PG(html_errors)) { - brlen = 7; - br = "
\n"; - } else { - brlen = 1; - br = "\n"; - } + if (strcmp(wrapper_name, PHP_STREAM_ERROR_WRAPPER_DEFAULT_NAME)) { + zend_llist *err_list = php_stream_get_wrapper_errors_list(wrapper_name); + if (err_list) { + size_t l = 0; + int brlen; + int i; + int count = (int) zend_llist_count(err_list); + const char *br; + php_stream_error_entry **err_entry_p; + zend_llist_position pos; + + if (PG(html_errors)) { + brlen = 7; + br = "
\n"; + } else { + brlen = 1; + br = "\n"; + } - for (err_entry_p = zend_llist_get_first_ex(err_list, &pos), i = 0; err_entry_p; - err_entry_p = zend_llist_get_next_ex(err_list, &pos), i++) { - l += ZSTR_LEN((*err_entry_p)->message); - if (i < count - 1) { - l += brlen; + for (err_entry_p = zend_llist_get_first_ex(err_list, &pos), i = 0; err_entry_p; + err_entry_p = zend_llist_get_next_ex(err_list, &pos), i++) { + l += ZSTR_LEN((*err_entry_p)->message); + if (i < count - 1) { + l += brlen; + } } - } - msg = emalloc(l + 1); - msg[0] = '\0'; - for (err_entry_p = zend_llist_get_first_ex(err_list, &pos), i = 0; err_entry_p; - err_entry_p = zend_llist_get_next_ex(err_list, &pos), i++) { - strcat(msg, ZSTR_VAL((*err_entry_p)->message)); - if (i < count - 1) { - strcat(msg, br); + msg = emalloc(l + 1); + msg[0] = '\0'; + for (err_entry_p = zend_llist_get_first_ex(err_list, &pos), i = 0; err_entry_p; + err_entry_p = zend_llist_get_next_ex(err_list, &pos), i++) { + strcat(msg, ZSTR_VAL((*err_entry_p)->message)); + if (i < count - 1) { + strcat(msg, br); + } } - } - free_msg = 1; - } else { - if (!strcmp(wrapper_name, php_plain_files_wrapper.wops->label)) { - msg = php_socket_strerror_s(errno, errstr, sizeof(errstr)); + free_msg = 1; } else { - msg = "operation failed"; + if (!strcmp(wrapper_name, php_plain_files_wrapper.wops->label)) { + msg = php_socket_strerror_s(errno, errstr, sizeof(errstr)); + } else { + msg = "operation failed"; + } } + } else { + msg = "no suitable wrapper could be found"; } php_strip_url_passwd(tmp); From 0ec44f1293225bdfa21792b079e11fdd2b25c5e1 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Thu, 20 Nov 2025 00:05:47 +0100 Subject: [PATCH 40/68] stream: generate optimizer info for stream_get_errors --- Zend/Optimizer/zend_func_infos.h | 1 + 1 file changed, 1 insertion(+) diff --git a/Zend/Optimizer/zend_func_infos.h b/Zend/Optimizer/zend_func_infos.h index b7b118c710c53..16d254b3a38fd 100644 --- a/Zend/Optimizer/zend_func_infos.h +++ b/Zend/Optimizer/zend_func_infos.h @@ -596,6 +596,7 @@ static const func_info_t func_infos[] = { F1("stream_get_line", MAY_BE_STRING|MAY_BE_FALSE), F1("stream_resolve_include_path", MAY_BE_STRING|MAY_BE_FALSE), F1("stream_get_wrappers", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_OF_STRING), + FN("stream_get_errors", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_OF_ARRAY), F1("stream_get_transports", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_OF_STRING), #if defined(HAVE_GETTIMEOFDAY) F1("uniqid", MAY_BE_STRING), From 26d3a8a7cc36662b77a2663e30f7574a1fe09498 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Thu, 20 Nov 2025 00:10:27 +0100 Subject: [PATCH 41/68] stream: make exception wrapper optional --- main/streams/stream_errors.stub.php | 4 ++-- main/streams/stream_errors_arginfo.h | 9 ++++----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/main/streams/stream_errors.stub.php b/main/streams/stream_errors.stub.php index fb6c5584a5f48..61779037fdc6c 100644 --- a/main/streams/stream_errors.stub.php +++ b/main/streams/stream_errors.stub.php @@ -4,11 +4,11 @@ class StreamException extends Exception { - protected string $wrapperName; + protected ?string $wrapperName = null; protected ?string $param = null; public function getParam(): ?string {} - public function getWrapperName(): string {} + public function getWrapperName(): ?string {} } /** diff --git a/main/streams/stream_errors_arginfo.h b/main/streams/stream_errors_arginfo.h index 79d86059dbdb6..5c21a632755a9 100644 --- a/main/streams/stream_errors_arginfo.h +++ b/main/streams/stream_errors_arginfo.h @@ -1,11 +1,10 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 97a63d009e4a3e951b0c3b213e9cb784d1af5634 */ + * Stub hash: afc1e2ff4a74033102ca8b69ea55ab9ce30986da */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_StreamException_getParam, 0, 0, IS_STRING, 1) ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_StreamException_getWrapperName, 0, 0, IS_STRING, 0) -ZEND_END_ARG_INFO() +#define arginfo_class_StreamException_getWrapperName arginfo_class_StreamException_getParam static ZEND_METHOD(StreamException, getParam); static ZEND_METHOD(StreamException, getWrapperName); @@ -112,9 +111,9 @@ static zend_class_entry *register_class_StreamException(zend_class_entry *class_ class_entry = zend_register_internal_class_with_flags(&ce, class_entry_Exception, 0); zval property_wrapperName_default_value; - ZVAL_UNDEF(&property_wrapperName_default_value); + ZVAL_NULL(&property_wrapperName_default_value); zend_string *property_wrapperName_name = zend_string_init("wrapperName", sizeof("wrapperName") - 1, true); - zend_declare_typed_property(class_entry, property_wrapperName_name, &property_wrapperName_default_value, ZEND_ACC_PROTECTED, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING)); + zend_declare_typed_property(class_entry, property_wrapperName_name, &property_wrapperName_default_value, ZEND_ACC_PROTECTED, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING|MAY_BE_NULL)); zend_string_release_ex(property_wrapperName_name, true); zval property_param_default_value; From b94fd18f8f41260fd0da4b4cf6326a56e1bc4f38 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Sun, 28 Dec 2025 16:19:53 +0100 Subject: [PATCH 42/68] stream: restructure error api --- ext/standard/basic_functions.stub.php | 5 +- ext/standard/basic_functions_arginfo.h | 9 +- ext/standard/basic_functions_decl.h | 8 +- ext/standard/file.h | 2 +- ext/standard/streamsfuncs.c | 113 +- .../tests/streams/stream_errors_chaining.phpt | 41 + ...stream_errors_error_code_helpers copy.phpt | 28 + .../stream_errors_error_has_code copy.phpt | 30 + ...stream_errors_exception_mode_terminal.phpt | 10 +- .../streams/stream_errors_invalid_types.phpt | 33 + .../stream_errors_mix_modes_storage.phpt | 192 +-- .../stream_errors_modes_with_auto_store.phpt | 30 +- .../streams/stream_errors_multi_store.phpt | 23 + .../stream_errors_silent_with_handler.phpt | 16 +- .../stream_errors_silent_with_storage.phpt | 20 +- .../stream_errors_silent_without_storage.phpt | 10 +- .../streams/stream_errors_standard_error.phpt | 2 +- main/streams/php_stream_errors.h | 362 +++-- main/streams/stream_errors.c | 1260 +++++++++++------ main/streams/stream_errors.stub.php | 481 +------ main/streams/stream_errors_arginfo.h | 246 ++-- main/streams/streams.c | 6 +- 22 files changed, 1584 insertions(+), 1343 deletions(-) create mode 100644 ext/standard/tests/streams/stream_errors_chaining.phpt create mode 100644 ext/standard/tests/streams/stream_errors_error_code_helpers copy.phpt create mode 100644 ext/standard/tests/streams/stream_errors_error_has_code copy.phpt create mode 100644 ext/standard/tests/streams/stream_errors_invalid_types.phpt create mode 100644 ext/standard/tests/streams/stream_errors_multi_store.phpt diff --git a/ext/standard/basic_functions.stub.php b/ext/standard/basic_functions.stub.php index 54e69905038fc..0d9312b5d13c8 100644 --- a/ext/standard/basic_functions.stub.php +++ b/ext/standard/basic_functions.stub.php @@ -3550,10 +3550,9 @@ function stream_resolve_include_path(string $filename): string|false {} function stream_get_wrappers(): array {} /** - * @param resource|string|null $subject - * @return array + * @refcount 1 */ -function stream_get_errors($subject = null): array {} +function stream_get_last_error(): ?StreamError {} /** * @return array diff --git a/ext/standard/basic_functions_arginfo.h b/ext/standard/basic_functions_arginfo.h index 1e9c88fd21b0a..47eafbbd04101 100644 --- a/ext/standard/basic_functions_arginfo.h +++ b/ext/standard/basic_functions_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit basic_functions.stub.php instead. - * Stub hash: a4b0db912b5cd5b7d36925da9f5d1cf9d6e19ba4 + * Stub hash: 49482b049ef53a19aef36947da4d3ce3aac50cdf * Has decl header: yes */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_set_time_limit, 0, 1, _IS_BOOL, 0) @@ -1987,8 +1987,7 @@ ZEND_END_ARG_INFO() #define arginfo_stream_get_wrappers arginfo_ob_list_handlers -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_stream_get_errors, 0, 0, IS_ARRAY, 0) - ZEND_ARG_INFO_WITH_DEFAULT_VALUE(0, subject, "null") +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_stream_get_last_error, 0, 0, StreamError, 1) ZEND_END_ARG_INFO() #define arginfo_stream_get_transports arginfo_ob_list_handlers @@ -2833,7 +2832,7 @@ ZEND_FUNCTION(stream_get_meta_data); ZEND_FUNCTION(stream_get_line); ZEND_FUNCTION(stream_resolve_include_path); ZEND_FUNCTION(stream_get_wrappers); -ZEND_FUNCTION(stream_get_errors); +ZEND_FUNCTION(stream_get_last_error); ZEND_FUNCTION(stream_get_transports); ZEND_FUNCTION(stream_is_local); ZEND_FUNCTION(stream_isatty); @@ -3442,7 +3441,7 @@ static const zend_function_entry ext_functions[] = { ZEND_FE(stream_get_line, arginfo_stream_get_line) ZEND_FE(stream_resolve_include_path, arginfo_stream_resolve_include_path) ZEND_FE(stream_get_wrappers, arginfo_stream_get_wrappers) - ZEND_FE(stream_get_errors, arginfo_stream_get_errors) + ZEND_FE(stream_get_last_error, arginfo_stream_get_last_error) ZEND_FE(stream_get_transports, arginfo_stream_get_transports) ZEND_FE(stream_is_local, arginfo_stream_is_local) ZEND_FE(stream_isatty, arginfo_stream_isatty) diff --git a/ext/standard/basic_functions_decl.h b/ext/standard/basic_functions_decl.h index c44ef56182fa6..32ef5e4e4b82c 100644 --- a/ext/standard/basic_functions_decl.h +++ b/ext/standard/basic_functions_decl.h @@ -1,8 +1,8 @@ /* This is a generated file, edit basic_functions.stub.php instead. - * Stub hash: a4b0db912b5cd5b7d36925da9f5d1cf9d6e19ba4 */ + * Stub hash: 49482b049ef53a19aef36947da4d3ce3aac50cdf */ -#ifndef ZEND_BASIC_FUNCTIONS_DECL_a4b0db912b5cd5b7d36925da9f5d1cf9d6e19ba4_H -#define ZEND_BASIC_FUNCTIONS_DECL_a4b0db912b5cd5b7d36925da9f5d1cf9d6e19ba4_H +#ifndef ZEND_BASIC_FUNCTIONS_DECL_49482b049ef53a19aef36947da4d3ce3aac50cdf_H +#define ZEND_BASIC_FUNCTIONS_DECL_49482b049ef53a19aef36947da4d3ce3aac50cdf_H typedef enum zend_enum_RoundingMode { ZEND_ENUM_RoundingMode_HalfAwayFromZero = 1, @@ -15,4 +15,4 @@ typedef enum zend_enum_RoundingMode { ZEND_ENUM_RoundingMode_PositiveInfinity = 8, } zend_enum_RoundingMode; -#endif /* ZEND_BASIC_FUNCTIONS_DECL_a4b0db912b5cd5b7d36925da9f5d1cf9d6e19ba4_H */ +#endif /* ZEND_BASIC_FUNCTIONS_DECL_49482b049ef53a19aef36947da4d3ce3aac50cdf_H */ diff --git a/ext/standard/file.h b/ext/standard/file.h index a3c84791cc1ee..6f08dad366f88 100644 --- a/ext/standard/file.h +++ b/ext/standard/file.h @@ -102,7 +102,7 @@ typedef struct { HashTable *stream_wrappers; /* per-request copy of url_stream_wrappers_hash */ HashTable *stream_filters; /* per-request copy of stream_filters_hash */ HashTable *wrapper_logged_errors; /* key: wrapper address; value: linked list of error entries */ - HashTable *wrapper_stored_errors; /* key: wrapper address; value: linked list of error entries */ + php_stream_error_state stream_error_state; int pclose_wait; #ifdef HAVE_GETHOSTBYNAME_R struct hostent tmp_host_info; diff --git a/ext/standard/streamsfuncs.c b/ext/standard/streamsfuncs.c index 6472bbc23dedc..e81e14c082175 100644 --- a/ext/standard/streamsfuncs.c +++ b/ext/standard/streamsfuncs.c @@ -594,102 +594,25 @@ PHP_FUNCTION(stream_get_wrappers) } /* }}} */ -/* Helper function to convert error list to array */ -static void php_stream_errors_list_to_array(zend_llist *list, zval *return_value) +/* Retrieves the last stored stream error */ +PHP_FUNCTION(stream_get_last_error) { - php_stream_error_entry **err_entry_p; - zend_llist_position pos; - - for (err_entry_p = zend_llist_get_first_ex(list, &pos); - err_entry_p; - err_entry_p = zend_llist_get_next_ex(list, &pos)) { - php_stream_error_entry *entry = *err_entry_p; - zval error_array; - array_init(&error_array); - - add_assoc_str(&error_array, "message", zend_string_copy(entry->message)); - add_assoc_long(&error_array, "code", entry->code); - add_assoc_long(&error_array, "severity", entry->severity); - add_assoc_bool(&error_array, "terminal", entry->terminal); - - if (entry->wrapper_name) { - add_assoc_string(&error_array, "wrapper", entry->wrapper_name); - } - if (entry->param) { - add_assoc_string(&error_array, "param", entry->param); - } - if (entry->docref) { - add_assoc_string(&error_array, "docref", entry->docref); - } - - add_next_index_zval(return_value, &error_array); - } -} - -/* Retrieves list of stored stream errors */ -PHP_FUNCTION(stream_get_errors) -{ - zval *subject = NULL; - php_stream *stream = NULL; - char *wrapper_name = NULL; - size_t wrapper_name_len = 0; - bool get_all_wrappers = false; - - ZEND_PARSE_PARAMETERS_START(0, 1) - Z_PARAM_OPTIONAL - Z_PARAM_ZVAL(subject) - ZEND_PARSE_PARAMETERS_END(); - - /* Determine what we're querying for */ - if (subject == NULL) { - /* No parameter - get all wrapper errors */ - get_all_wrappers = true; - } else if (Z_TYPE_P(subject) == IS_RESOURCE) { - /* Stream resource - get errors for this stream */ - php_stream_from_zval_no_verify(stream, subject); - if (stream == NULL) { - zend_argument_type_error(1, "must be a valid stream resource"); - RETURN_THROWS(); - } - } else if (Z_TYPE_P(subject) == IS_STRING) { - /* Wrapper name - get errors for this wrapper */ - wrapper_name = Z_STRVAL_P(subject); - wrapper_name_len = Z_STRLEN_P(subject); - } else { - zend_argument_type_error(1, "must be a stream resource, string, or null"); - RETURN_THROWS(); - } - - array_init(return_value); - - /* Handle stream errors */ - if (stream) { - if (stream->error_list) { - php_stream_errors_list_to_array(stream->error_list, return_value); - } - } else if (get_all_wrappers) { - /* Get errors from all wrappers */ - if (FG(wrapper_stored_errors)) { - zend_string *key; - zval *val; - ZEND_HASH_FOREACH_STR_KEY_VAL(FG(wrapper_stored_errors), key, val) { - if (key) { - zend_llist *list = (zend_llist *) Z_PTR_P(val); - php_stream_errors_list_to_array(list, return_value); - } - } ZEND_HASH_FOREACH_END(); - } - } else if (wrapper_name) { - /* Get errors for specific wrapper */ - if (FG(wrapper_stored_errors)) { - zend_llist *list = zend_hash_str_find_ptr( - FG(wrapper_stored_errors), wrapper_name, wrapper_name_len); - - if (list) { - php_stream_errors_list_to_array(list, return_value); - } - } - } + ZEND_PARSE_PARAMETERS_NONE(); + + /* Check if we have any stored errors */ + if (!FG(stream_error_state).stored_errors) { + RETURN_NULL(); + } + + /* Get the most recent stored error (head of list) */ + php_stream_stored_error *stored = FG(stream_error_state).stored_errors; + + if (!stored->first_error) { + RETURN_NULL(); + } + + /* Create StreamError object from the error chain */ + php_stream_error_create_object(return_value, stored->first_error); } /* {{{ stream_select related functions */ diff --git a/ext/standard/tests/streams/stream_errors_chaining.phpt b/ext/standard/tests/streams/stream_errors_chaining.phpt new file mode 100644 index 0000000000000..859e468d3f5ee --- /dev/null +++ b/ext/standard/tests/streams/stream_errors_chaining.phpt @@ -0,0 +1,41 @@ +--TEST-- +Stream errors - error chaining +--FILE-- + [ + 'error_mode' => StreamErrorMode::Silent, + 'error_store' => StreamErrorStore::All, + ] +]); + +$stream = fopen('test://foo', 'r', false, $context); + +$error = stream_get_last_error(); +if ($error) { + echo "Error count: " . $error->count() . "\n"; + echo "First error: " . $error->message . "\n"; + + // Check if it has next error + if ($error->next) { + echo "Has chained error: yes\n"; + } +} + +?> +--EXPECTF-- +Error count: %d +First error: %s +%a diff --git a/ext/standard/tests/streams/stream_errors_error_code_helpers copy.phpt b/ext/standard/tests/streams/stream_errors_error_code_helpers copy.phpt new file mode 100644 index 0000000000000..c52bafb52c6f1 --- /dev/null +++ b/ext/standard/tests/streams/stream_errors_error_code_helpers copy.phpt @@ -0,0 +1,28 @@ +--TEST-- +Stream errors - StreamErrorCode helper methods +--FILE-- + [ + 'error_mode' => StreamErrorMode::Silent, + ] +]); + +// Generate a network error +$stream = @fsockopen('invalid-host-12345.example.com', 80, $errno, $errstr, 1, $context); + +$error = stream_get_last_error(); +if ($error) { + echo "Is I/O error: " . ($error->code->isIoError() ? 'yes' : 'no') . "\n"; + echo "Is filesystem error: " . ($error->code->isFileSystemError() ? 'yes' : 'no') . "\n"; + echo "Is network error: " . ($error->code->isNetworkError() ? 'yes' : 'no') . "\n"; + echo "Is wrapper error: " . ($error->code->isWrapperError() ? 'yes' : 'no') . "\n"; +} + +?> +--EXPECTF-- +Is I/O error: %s +Is filesystem error: no +Is network error: %s +Is wrapper error: %s diff --git a/ext/standard/tests/streams/stream_errors_error_has_code copy.phpt b/ext/standard/tests/streams/stream_errors_error_has_code copy.phpt new file mode 100644 index 0000000000000..2bd9595f67876 --- /dev/null +++ b/ext/standard/tests/streams/stream_errors_error_has_code copy.phpt @@ -0,0 +1,30 @@ +--TEST-- +Stream errors - multiple operations stored +--FILE-- + [ + 'error_mode' => StreamErrorMode::Silent, + 'error_store' => StreamErrorStore::All, + ] +]); + +// First operation +$stream1 = fopen('php://nonexistent1', 'r', false, $context); +$error1 = stream_get_last_error(); + +// Second operation +$stream2 = fopen('php://nonexistent2', 'r', false, $context); +$error2 = stream_get_last_error(); + +// Should get the most recent error (second operation) +if ($error2) { + echo "Got most recent error\n"; + echo "Param contains 'nonexistent2': " . (strpos($error2->param ?? '', 'nonexistent2') !== false ? 'yes' : 'no') . "\n"; +} + +?> +--EXPECT-- +Got most recent error +Param contains 'nonexistent2': yes diff --git a/ext/standard/tests/streams/stream_errors_exception_mode_terminal.phpt b/ext/standard/tests/streams/stream_errors_exception_mode_terminal.phpt index 016b989276fa0..d66e6d654f1df 100644 --- a/ext/standard/tests/streams/stream_errors_exception_mode_terminal.phpt +++ b/ext/standard/tests/streams/stream_errors_exception_mode_terminal.phpt @@ -5,7 +5,7 @@ Stream errors - exception mode for terminal errors $context = stream_context_create([ 'stream' => [ - 'error_mode' => STREAM_ERROR_MODE_EXCEPTION, + 'error_mode' => StreamErrorMode::Exception, ] ]); @@ -14,7 +14,12 @@ try { } catch (StreamException $e) { echo "Caught: " . $e->getMessage() . "\n"; echo "Code: " . $e->getCode() . "\n"; - echo "Wrapper: " . $e->getWrapperName() . "\n"; + + $error = $e->getError(); + if ($error) { + echo "Wrapper: " . $error->wrapperName . "\n"; + echo "Error code name: " . $error->code->name . "\n"; + } } ?> @@ -22,3 +27,4 @@ try { Caught: Failed to open stream: operation failed Code: 36 Wrapper: PHP +Error code name: OpenFailed diff --git a/ext/standard/tests/streams/stream_errors_invalid_types.phpt b/ext/standard/tests/streams/stream_errors_invalid_types.phpt new file mode 100644 index 0000000000000..22563920ed672 --- /dev/null +++ b/ext/standard/tests/streams/stream_errors_invalid_types.phpt @@ -0,0 +1,33 @@ +--TEST-- +Stream errors - invalid enum type throws TypeError +--FILE-- + [ + 'error_mode' => 'invalid', + ] + ]); + + fopen('php://nonexistent', 'r', false, $context); +} catch (TypeError $e) { + echo "Caught TypeError for error_mode\n"; +} + +try { + $context = stream_context_create([ + 'stream' => [ + 'error_store' => 123, + ] + ]); + + fopen('php://nonexistent', 'r', false, $context); +} catch (TypeError $e) { + echo "Caught TypeError for error_store\n"; +} + +?> +--EXPECT-- +Caught TypeError for error_mode +Caught TypeError for error_store diff --git a/ext/standard/tests/streams/stream_errors_mix_modes_storage.phpt b/ext/standard/tests/streams/stream_errors_mix_modes_storage.phpt index cb765de62fe07..80dd85a4a386b 100644 --- a/ext/standard/tests/streams/stream_errors_mix_modes_storage.phpt +++ b/ext/standard/tests/streams/stream_errors_mix_modes_storage.phpt @@ -31,158 +31,117 @@ function stream_test_errors($title, $context) { $stream = fopen('test://foo', 'r', false, $context); try { echo $title . "\n"; - $readin = fopen( 'php://stdin', 'r' ); - $data = fread( $stream, 10 ); + $readin = fopen('php://stdin', 'r'); + $data = fread($stream, 10); - $read = [$readin, $stream]; - $write = NULL; + $read = [$readin, $stream]; + $write = NULL; $except = NULL; stream_select($read, $write, $except, 0); } catch (StreamException $e) { echo 'EXCEPTION: ' . $e->getMessage() . "\n"; } - $errors = stream_get_errors($stream); - var_dump($errors); + $error = stream_get_last_error(); + if ($error) { + echo "Error details:\n"; + echo "- Message: " . $error->message . "\n"; + echo "- Code: " . $error->code->name . " (" . $error->code->value . ")\n"; + echo "- Wrapper: " . $error->wrapperName . "\n"; + echo "- Terminating: " . ($error->terminating ? 'yes' : 'no') . "\n"; + echo "- Count: " . $error->count() . "\n"; + + // Show all errors in chain + $current = $error; + $idx = 0; + while ($current) { + echo " [$idx] " . $current->code->name . ": " . substr($current->message, 0, 50) . "...\n"; + $current = $current->next; + $idx++; + } + } else { + echo "No errors stored\n"; + } + echo "\n"; } stream_test_errors('ALL', stream_context_create([ 'stream' => [ - 'error_mode' => STREAM_ERROR_MODE_SILENT, - 'error_store' => STREAM_ERROR_STORE_ALL, + 'error_mode' => StreamErrorMode::Silent, + 'error_store' => StreamErrorStore::All, ] ])); + stream_test_errors('NON TERMINAL', stream_context_create([ 'stream' => [ - 'error_mode' => STREAM_ERROR_MODE_SILENT, - 'error_store' => STREAM_ERROR_STORE_NON_TERMINAL, + 'error_mode' => StreamErrorMode::Silent, + 'error_store' => StreamErrorStore::NonTerminal, ] ])); + stream_test_errors('TERMINAL', stream_context_create([ 'stream' => [ - 'error_mode' => STREAM_ERROR_MODE_SILENT, - 'error_store' => STREAM_ERROR_STORE_TERMINAL, + 'error_mode' => StreamErrorMode::Silent, + 'error_store' => StreamErrorStore::Terminal, ] ])); + stream_test_errors('AUTO EXCEPTION', stream_context_create([ 'stream' => [ - 'error_mode' => STREAM_ERROR_MODE_EXCEPTION, - 'error_store' => STREAM_ERROR_STORE_AUTO, + 'error_mode' => StreamErrorMode::Exception, + 'error_store' => StreamErrorStore::Auto, ] ])); + stream_test_errors('AUTO ERROR', stream_context_create([ 'stream' => [ - 'error_mode' => STREAM_ERROR_MODE_ERROR, - 'error_store' => STREAM_ERROR_STORE_AUTO, + 'error_mode' => StreamErrorMode::Error, + 'error_store' => StreamErrorStore::Auto, ] ])); ?> --EXPECTF-- ALL -array(3) { - [0]=> - array(5) { - ["message"]=> - string(113) "TestStream::stream_read - read 10 bytes more data than requested (8202 read, 8192 max) - excess data will be lost" - ["code"]=> - int(161) - ["severity"]=> - int(2) - ["terminal"]=> - bool(false) - ["wrapper"]=> - string(10) "user-space" - } - [1]=> - array(5) { - ["message"]=> - string(43) "TestStream::stream_cast is not implemented!" - ["code"]=> - int(70) - ["severity"]=> - int(2) - ["terminal"]=> - bool(true) - ["wrapper"]=> - string(10) "user-space" - } - [2]=> - array(5) { - ["message"]=> - string(73) "Cannot represent a stream of type user-space as a select()able descriptor" - ["code"]=> - int(101) - ["severity"]=> - int(2) - ["terminal"]=> - bool(true) - ["wrapper"]=> - string(10) "user-space" - } -} +Error details: +- Message: TestStream::stream_read - read 10 bytes more data than requested (8202 read, 8192 max) - excess data will be lost +- Code: UserspaceInvalidReturn (161) +- Wrapper: user-space +- Terminating: no +- Count: 3 + [0] UserspaceInvalidReturn: TestStream::stream_read - read 10 bytes more data ... + [1] NotImplemented: TestStream::stream_cast is not implemented!... + [2] CastNotSupported: Cannot represent a stream of type user-space as... + NON TERMINAL -array(1) { - [0]=> - array(5) { - ["message"]=> - string(113) "TestStream::stream_read - read 10 bytes more data than requested (8202 read, 8192 max) - excess data will be lost" - ["code"]=> - int(161) - ["severity"]=> - int(2) - ["terminal"]=> - bool(false) - ["wrapper"]=> - string(10) "user-space" - } -} +Error details: +- Message: TestStream::stream_read - read 10 bytes more data than requested (8202 read, 8192 max) - excess data will be lost +- Code: UserspaceInvalidReturn (161) +- Wrapper: user-space +- Terminating: no +- Count: 1 + [0] UserspaceInvalidReturn: TestStream::stream_read - read 10 bytes more data ... + TERMINAL -array(2) { - [0]=> - array(5) { - ["message"]=> - string(43) "TestStream::stream_cast is not implemented!" - ["code"]=> - int(70) - ["severity"]=> - int(2) - ["terminal"]=> - bool(true) - ["wrapper"]=> - string(10) "user-space" - } - [1]=> - array(5) { - ["message"]=> - string(73) "Cannot represent a stream of type user-space as a select()able descriptor" - ["code"]=> - int(101) - ["severity"]=> - int(2) - ["terminal"]=> - bool(true) - ["wrapper"]=> - string(10) "user-space" - } -} +Error details: +- Message: TestStream::stream_cast is not implemented! +- Code: NotImplemented (70) +- Wrapper: user-space +- Terminating: yes +- Count: 2 + [0] NotImplemented: TestStream::stream_cast is not implemented!... + [1] CastNotSupported: Cannot represent a stream of type user-space as... + AUTO EXCEPTION EXCEPTION: Cannot represent a stream of type user-space as a select()able descriptor -array(1) { - [0]=> - array(5) { - ["message"]=> - string(113) "TestStream::stream_read - read 10 bytes more data than requested (8202 read, 8192 max) - excess data will be lost" - ["code"]=> - int(161) - ["severity"]=> - int(2) - ["terminal"]=> - bool(false) - ["wrapper"]=> - string(10) "user-space" - } -} +Error details: +- Message: TestStream::stream_read - read 10 bytes more data than requested (8202 read, 8192 max) - excess data will be lost +- Code: UserspaceInvalidReturn (161) +- Wrapper: user-space +- Terminating: no +- Count: 1 + [0] UserspaceInvalidReturn: TestStream::stream_read - read 10 bytes more data ... + AUTO ERROR Warning: fread(): TestStream::stream_read - read 10 bytes more data than requested (8202 read, 8192 max) - excess data will be lost in %s on line %d @@ -190,5 +149,4 @@ Warning: fread(): TestStream::stream_read - read 10 bytes more data than request Warning: stream_select(): TestStream::stream_cast is not implemented! in %s on line %d Warning: stream_select(): Cannot represent a stream of type user-space as a select()able descriptor in %s on line %d -array(0) { -} +No errors stored diff --git a/ext/standard/tests/streams/stream_errors_modes_with_auto_store.phpt b/ext/standard/tests/streams/stream_errors_modes_with_auto_store.phpt index bda445eabe428..cfc776c437db2 100644 --- a/ext/standard/tests/streams/stream_errors_modes_with_auto_store.phpt +++ b/ext/standard/tests/streams/stream_errors_modes_with_auto_store.phpt @@ -6,20 +6,20 @@ Stream errors - error_store AUTO mode behavior // AUTO with ERROR mode should store NONE $context1 = stream_context_create([ 'stream' => [ - 'error_mode' => STREAM_ERROR_MODE_ERROR, - 'error_store' => STREAM_ERROR_STORE_AUTO, + 'error_mode' => StreamErrorMode::Error, + 'error_store' => StreamErrorStore::Auto, ] ]); @fopen('php://nonexistent', 'r', false, $context1); -$errors1 = stream_get_errors('PHP'); -echo "ERROR mode AUTO: " . count($errors1) . "\n"; +$error1 = stream_get_last_error(); +echo "ERROR mode AUTO: " . ($error1 ? "has error" : "no error") . "\n"; // AUTO with EXCEPTION mode should store NON_TERM $context2 = stream_context_create([ 'stream' => [ - 'error_mode' => STREAM_ERROR_MODE_EXCEPTION, - 'error_store' => STREAM_ERROR_STORE_AUTO, + 'error_mode' => StreamErrorMode::Exception, + 'error_store' => StreamErrorStore::Auto, ] ]); @@ -27,23 +27,23 @@ try { fopen('php://nonexistent2', 'r', false, $context2); } catch (StreamException $e) {} -$errors2 = stream_get_errors('PHP'); -echo "EXCEPTION mode AUTO: " . count($errors2) . "\n"; +$error2 = stream_get_last_error(); +echo "EXCEPTION mode AUTO: " . ($error2 ? "has error" : "no error") . "\n"; // AUTO with SILENT mode should store ALL $context3 = stream_context_create([ 'stream' => [ - 'error_mode' => STREAM_ERROR_MODE_SILENT, - 'error_store' => STREAM_ERROR_STORE_AUTO, + 'error_mode' => StreamErrorMode::Silent, + 'error_store' => StreamErrorStore::Auto, ] ]); fopen('php://nonexistent3', 'r', false, $context3); -$errors3 = stream_get_errors('PHP'); -echo "SILENT mode AUTO: " . count($errors3) . "\n"; +$error3 = stream_get_last_error(); +echo "SILENT mode AUTO: " . ($error3 ? "has error" : "no error") . "\n"; ?> --EXPECTF-- -ERROR mode AUTO: 0 -EXCEPTION mode AUTO: %d -SILENT mode AUTO: %d +ERROR mode AUTO: no error +EXCEPTION mode AUTO: %s +SILENT mode AUTO: has error diff --git a/ext/standard/tests/streams/stream_errors_multi_store.phpt b/ext/standard/tests/streams/stream_errors_multi_store.phpt new file mode 100644 index 0000000000000..eccfb065d563c --- /dev/null +++ b/ext/standard/tests/streams/stream_errors_multi_store.phpt @@ -0,0 +1,23 @@ +--TEST-- +Stream errors - StreamError hasCode method +--FILE-- + [ + 'error_mode' => StreamErrorMode::Silent, + ] +]); + +$stream = fopen('php://nonexistent', 'r', false, $context); + +$error = stream_get_last_error(); +if ($error) { + echo "Has OpenFailed: " . ($error->hasCode(StreamErrorCode::OpenFailed) ? 'yes' : 'no') . "\n"; + echo "Has NotFound: " . ($error->hasCode(StreamErrorCode::NotFound) ? 'yes' : 'no') . "\n"; +} + +?> +--EXPECT-- +Has OpenFailed: yes +Has NotFound: no diff --git a/ext/standard/tests/streams/stream_errors_silent_with_handler.phpt b/ext/standard/tests/streams/stream_errors_silent_with_handler.phpt index 9ce86adb09658..2416a15529aa5 100644 --- a/ext/standard/tests/streams/stream_errors_silent_with_handler.phpt +++ b/ext/standard/tests/streams/stream_errors_silent_with_handler.phpt @@ -7,14 +7,15 @@ $handler_called = false; $context = stream_context_create([ 'stream' => [ - 'error_mode' => STREAM_ERROR_MODE_SILENT, - 'error_handler' => function($wrapper, $stream, $code, $message, $param) use (&$handler_called) { + 'error_mode' => StreamErrorMode::Silent, + 'error_handler' => function(StreamError $error) use (&$handler_called) { $handler_called = true; echo "Handler called\n"; - echo "Wrapper: $wrapper\n"; - echo "Code: $code\n"; - echo "Message: $message\n"; - echo "Param: " . ($param ?? 'null') . "\n"; + echo "Wrapper: " . $error->wrapperName . "\n"; + echo "Code: " . $error->code->name . "\n"; + echo "Message: " . $error->message . "\n"; + echo "Param: " . ($error->param ?? 'null') . "\n"; + echo "Terminating: " . ($error->terminating ? 'yes' : 'no') . "\n"; } ] ]); @@ -27,7 +28,8 @@ var_dump($handler_called); --EXPECT-- Handler called Wrapper: PHP -Code: 36 +Code: OpenFailed Message: Failed to open stream: operation failed Param: php://nonexistent +Terminating: yes bool(true) diff --git a/ext/standard/tests/streams/stream_errors_silent_with_storage.phpt b/ext/standard/tests/streams/stream_errors_silent_with_storage.phpt index 563857d308fff..0d3d627001788 100644 --- a/ext/standard/tests/streams/stream_errors_silent_with_storage.phpt +++ b/ext/standard/tests/streams/stream_errors_silent_with_storage.phpt @@ -5,23 +5,25 @@ Stream errors - silent mode with error storage $context = stream_context_create([ 'stream' => [ - 'error_mode' => STREAM_ERROR_MODE_SILENT, + 'error_mode' => StreamErrorMode::Silent, ] ]); $stream = fopen('php://nonexistent', 'r', false, $context); var_dump($stream); -$errors = stream_get_errors(); -echo "Error count: " . count($errors) . "\n"; -if (count($errors) > 0) { - echo "First error code: " . $errors[0]['code'] . "\n"; - echo "First error wrapper: " . $errors[0]['wrapper'] . "\n"; +$error = stream_get_last_error(); +if ($error) { + echo "Has error: yes\n"; + echo "Error code: " . $error->code->name . "\n"; + echo "Error wrapper: " . $error->wrapperName . "\n"; + echo "Error message: " . $error->message . "\n"; } ?> --EXPECT-- bool(false) -Error count: 1 -First error code: 36 -First error wrapper: PHP +Has error: yes +Error code: OpenFailed +Error wrapper: PHP +Error message: Failed to open stream: operation failed diff --git a/ext/standard/tests/streams/stream_errors_silent_without_storage.phpt b/ext/standard/tests/streams/stream_errors_silent_without_storage.phpt index 6ed79378d8226..477bbd7401c26 100644 --- a/ext/standard/tests/streams/stream_errors_silent_without_storage.phpt +++ b/ext/standard/tests/streams/stream_errors_silent_without_storage.phpt @@ -5,16 +5,16 @@ Stream errors - error_store NONE option $context = stream_context_create([ 'stream' => [ - 'error_mode' => STREAM_ERROR_MODE_SILENT, - 'error_store' => STREAM_ERROR_STORE_NONE, + 'error_mode' => StreamErrorMode::Silent, + 'error_store' => StreamErrorStore::None, ] ]); $stream = fopen('php://nonexistent', 'r', false, $context); -$errors = stream_get_errors(); -echo "Error count: " . count($errors) . "\n"; +$error = stream_get_last_error(); +echo "Has error: " . ($error ? "yes" : "no") . "\n"; ?> --EXPECT-- -Error count: 0 +Has error: no diff --git a/ext/standard/tests/streams/stream_errors_standard_error.phpt b/ext/standard/tests/streams/stream_errors_standard_error.phpt index a9725f0b89b26..42de8cc3b17df 100644 --- a/ext/standard/tests/streams/stream_errors_standard_error.phpt +++ b/ext/standard/tests/streams/stream_errors_standard_error.phpt @@ -5,7 +5,7 @@ Stream errors - error mode with standard error reporting $context = stream_context_create([ 'stream' => [ - 'error_mode' => STREAM_ERROR_MODE_ERROR, + 'error_mode' => StreamErrorMode::Error, ] ]); diff --git a/main/streams/php_stream_errors.h b/main/streams/php_stream_errors.h index a519149285e66..783e9b5150e3f 100644 --- a/main/streams/php_stream_errors.h +++ b/main/streams/php_stream_errors.h @@ -22,214 +22,284 @@ BEGIN_EXTERN_C() -/* Error mode context options */ -#define PHP_STREAM_ERROR_MODE_ERROR 0 -#define PHP_STREAM_ERROR_MODE_EXCEPTION 1 -#define PHP_STREAM_ERROR_MODE_SILENT 2 - -/* Error store context options */ -#define PHP_STREAM_ERROR_STORE_AUTO 0 -#define PHP_STREAM_ERROR_STORE_NONE 1 -#define PHP_STREAM_ERROR_STORE_NON_TERM 2 -#define PHP_STREAM_ERROR_STORE_TERMINAL 3 -#define PHP_STREAM_ERROR_STORE_ALL 4 - -/* Stream Error Codes*/ -/* No error */ -#define STREAM_ERROR_CODE_NONE 0 -/* Generic unspecified error */ -#define STREAM_ERROR_CODE_GENERIC 1 -/* Stream I/O operations */ -#define STREAM_ERROR_CODE_READ_FAILED 10 -#define STREAM_ERROR_CODE_WRITE_FAILED 11 -#define STREAM_ERROR_CODE_SEEK_FAILED 12 -#define STREAM_ERROR_CODE_SEEK_NOT_SUPPORTED 13 -#define STREAM_ERROR_CODE_FLUSH_FAILED 14 -#define STREAM_ERROR_CODE_TRUNCATE_FAILED 15 -#define STREAM_ERROR_CODE_CONNECT_FAILED 16 -#define STREAM_ERROR_CODE_BIND_FAILED 17 -#define STREAM_ERROR_CODE_LISTEN_FAILED 18 -#define STREAM_ERROR_CODE_NOT_WRITABLE 19 -#define STREAM_ERROR_CODE_NOT_READABLE 20 -/* File system operations */ -#define STREAM_ERROR_CODE_DISABLED 30 -#define STREAM_ERROR_CODE_NOT_FOUND 31 -#define STREAM_ERROR_CODE_PERMISSION_DENIED 32 -#define STREAM_ERROR_CODE_ALREADY_EXISTS 33 -#define STREAM_ERROR_CODE_INVALID_PATH 34 -#define STREAM_ERROR_CODE_PATH_TOO_LONG 35 -#define STREAM_ERROR_CODE_OPEN_FAILED 36 -#define STREAM_ERROR_CODE_CREATE_FAILED 37 -#define STREAM_ERROR_CODE_DUP_FAILED 38 -#define STREAM_ERROR_CODE_UNLINK_FAILED 39 -#define STREAM_ERROR_CODE_RENAME_FAILED 40 -#define STREAM_ERROR_CODE_MKDIR_FAILED 41 -#define STREAM_ERROR_CODE_RMDIR_FAILED 42 -#define STREAM_ERROR_CODE_STAT_FAILED 43 -#define STREAM_ERROR_CODE_META_FAILED 44 -#define STREAM_ERROR_CODE_CHMOD_FAILED 45 -#define STREAM_ERROR_CODE_CHOWN_FAILED 46 -#define STREAM_ERROR_CODE_COPY_FAILED 47 -#define STREAM_ERROR_CODE_TOUCH_FAILED 48 -#define STREAM_ERROR_CODE_INVALID_MODE 49 -#define STREAM_ERROR_CODE_INVALID_META 50 -#define STREAM_ERROR_CODE_MODE_NOT_SUPPORTED 51 -#define STREAM_ERROR_CODE_READONLY 52 -#define STREAM_ERROR_CODE_RECURSION_DETECTED 53 -/* Wrapper/protocol operations */ -#define STREAM_ERROR_CODE_NOT_IMPLEMENTED 70 -#define STREAM_ERROR_CODE_NO_OPENER 71 -#define STREAM_ERROR_CODE_PERSISTENT_NOT_SUPPORTED 72 -#define STREAM_ERROR_CODE_WRAPPER_NOT_FOUND 73 -#define STREAM_ERROR_CODE_WRAPPER_DISABLED 74 -#define STREAM_ERROR_CODE_PROTOCOL_UNSUPPORTED 75 -#define STREAM_ERROR_CODE_WRAPPER_REGISTRATION_FAILED 76 -#define STREAM_ERROR_CODE_WRAPPER_UNREGISTRATION_FAILED 77 -#define STREAM_ERROR_CODE_WRAPPER_RESTORATION_FAILED 78 -/* Filter operations */ -#define STREAM_ERROR_CODE_FILTER_NOT_FOUND 90 -#define STREAM_ERROR_CODE_FILTER_FAILED 91 -/* Cast/conversion operations */ -#define STREAM_ERROR_CODE_CAST_FAILED 100 -#define STREAM_ERROR_CODE_CAST_NOT_SUPPORTED 101 -#define STREAM_ERROR_CODE_MAKE_SEEKABLE_FAILED 102 -#define STREAM_ERROR_CODE_BUFFERED_DATA_LOST 103 -/* Network/socket operations */ -#define STREAM_ERROR_CODE_NETWORK_SEND_FAILED 110 -#define STREAM_ERROR_CODE_NETWORK_RECV_FAILED 111 -#define STREAM_ERROR_CODE_SSL_NOT_SUPPORTED 112 -#define STREAM_ERROR_CODE_RESUMPTION_FAILED 113 -#define STREAM_ERROR_CODE_SOCKET_PATH_TOO_LONG 114 -#define STREAM_ERROR_CODE_OOB_NOT_SUPPORTED 115 -#define STREAM_ERROR_CODE_PROTOCOL_ERROR 116 -#define STREAM_ERROR_CODE_INVALID_URL 117 -#define STREAM_ERROR_CODE_INVALID_RESPONSE 118 -#define STREAM_ERROR_CODE_INVALID_HEADER 119 -#define STREAM_ERROR_CODE_INVALID_PARAM 110 -#define STREAM_ERROR_CODE_REDIRECT_LIMIT 121 -#define STREAM_ERROR_CODE_AUTH_FAILED 122 -/* Encoding/decoding/archiving operations */ -#define STREAM_ERROR_CODE_ARCHIVING_FAILED 130 -#define STREAM_ERROR_CODE_ENCODING_FAILED 131 -#define STREAM_ERROR_CODE_DECODING_FAILED 132 -#define STREAM_ERROR_CODE_INVALID_FORMAT 133 -/* Resource/allocation operations */ -#define STREAM_ERROR_CODE_ALLOCATION_FAILED 140 -#define STREAM_ERROR_CODE_TEMPORARY_FILE_FAILED 141 -/* Locking operations */ -#define STREAM_ERROR_CODE_LOCK_FAILED 150 -#define STREAM_ERROR_CODE_LOCK_NOT_SUPPORTED 151 -/* Userspace stream operations */ -#define STREAM_ERROR_CODE_USERSPACE_NOT_IMPLEMENTED 160 -#define STREAM_ERROR_CODE_USERSPACE_INVALID_RETURN 161 -#define STREAM_ERROR_CODE_USERSPACE_CALL_FAILED 162 +/* Error mode context options (internal C constants) */ +#define PHP_STREAM_ERROR_MODE_ERROR 0 +#define PHP_STREAM_ERROR_MODE_EXCEPTION 1 +#define PHP_STREAM_ERROR_MODE_SILENT 2 + +/* Error store context options (internal C constants) */ +#define PHP_STREAM_ERROR_STORE_AUTO 0 +#define PHP_STREAM_ERROR_STORE_NONE 1 +#define PHP_STREAM_ERROR_STORE_NON_TERM 2 +#define PHP_STREAM_ERROR_STORE_TERMINAL 3 +#define PHP_STREAM_ERROR_STORE_ALL 4 + +/* Maximum operation nesting depth */ +#define PHP_STREAM_ERROR_MAX_DEPTH 100 + +/* Error code ranges */ +#define STREAM_ERROR_CODE_IO_START 10 +#define STREAM_ERROR_CODE_IO_END 30 +#define STREAM_ERROR_CODE_FILESYSTEM_START 30 +#define STREAM_ERROR_CODE_FILESYSTEM_END 70 +#define STREAM_ERROR_CODE_WRAPPER_START 70 +#define STREAM_ERROR_CODE_WRAPPER_END 90 +#define STREAM_ERROR_CODE_FILTER_START 90 +#define STREAM_ERROR_CODE_FILTER_END 100 +#define STREAM_ERROR_CODE_CAST_START 100 +#define STREAM_ERROR_CODE_CAST_END 110 +#define STREAM_ERROR_CODE_NETWORK_START 110 +#define STREAM_ERROR_CODE_NETWORK_END 130 +#define STREAM_ERROR_CODE_ENCODING_START 130 +#define STREAM_ERROR_CODE_ENCODING_END 140 +#define STREAM_ERROR_CODE_RESOURCE_START 140 +#define STREAM_ERROR_CODE_RESOURCE_END 150 +#define STREAM_ERROR_CODE_LOCK_START 150 +#define STREAM_ERROR_CODE_LOCK_END 160 +#define STREAM_ERROR_CODE_USERSPACE_START 160 +#define STREAM_ERROR_CODE_USERSPACE_END 170 + +/* X-macro defining all error codes */ +#define PHP_STREAM_ERROR_CODES(V) \ + /* General errors */ \ + V(NONE, None, 0) \ + V(GENERIC, Generic, 1) \ + /* I/O operation errors (10-29) */ \ + V(READ_FAILED, ReadFailed, 10) \ + V(WRITE_FAILED, WriteFailed, 11) \ + V(SEEK_FAILED, SeekFailed, 12) \ + V(SEEK_NOT_SUPPORTED, SeekNotSupported, 13) \ + V(FLUSH_FAILED, FlushFailed, 14) \ + V(TRUNCATE_FAILED, TruncateFailed, 15) \ + V(CONNECT_FAILED, ConnectFailed, 16) \ + V(BIND_FAILED, BindFailed, 17) \ + V(LISTEN_FAILED, ListenFailed, 18) \ + V(NOT_WRITABLE, NotWritable, 19) \ + V(NOT_READABLE, NotReadable, 20) \ + /* File system operations (30-69) */ \ + V(DISABLED, Disabled, 30) \ + V(NOT_FOUND, NotFound, 31) \ + V(PERMISSION_DENIED, PermissionDenied, 32) \ + V(ALREADY_EXISTS, AlreadyExists, 33) \ + V(INVALID_PATH, InvalidPath, 34) \ + V(PATH_TOO_LONG, PathTooLong, 35) \ + V(OPEN_FAILED, OpenFailed, 36) \ + V(CREATE_FAILED, CreateFailed, 37) \ + V(DUP_FAILED, DupFailed, 38) \ + V(UNLINK_FAILED, UnlinkFailed, 39) \ + V(RENAME_FAILED, RenameFailed, 40) \ + V(MKDIR_FAILED, MkdirFailed, 41) \ + V(RMDIR_FAILED, RmdirFailed, 42) \ + V(STAT_FAILED, StatFailed, 43) \ + V(META_FAILED, MetaFailed, 44) \ + V(CHMOD_FAILED, ChmodFailed, 45) \ + V(CHOWN_FAILED, ChownFailed, 46) \ + V(COPY_FAILED, CopyFailed, 47) \ + V(TOUCH_FAILED, TouchFailed, 48) \ + V(INVALID_MODE, InvalidMode, 49) \ + V(INVALID_META, InvalidMeta, 50) \ + V(MODE_NOT_SUPPORTED, ModeNotSupported, 51) \ + V(READONLY, Readonly, 52) \ + V(RECURSION_DETECTED, RecursionDetected, 53) \ + /* Wrapper/protocol operations (70-89) */ \ + V(NOT_IMPLEMENTED, NotImplemented, 70) \ + V(NO_OPENER, NoOpener, 71) \ + V(PERSISTENT_NOT_SUPPORTED, PersistentNotSupported, 72) \ + V(WRAPPER_NOT_FOUND, WrapperNotFound, 73) \ + V(WRAPPER_DISABLED, WrapperDisabled, 74) \ + V(PROTOCOL_UNSUPPORTED, ProtocolUnsupported, 75) \ + V(WRAPPER_REGISTRATION_FAILED, WrapperRegistrationFailed, 76) \ + V(WRAPPER_UNREGISTRATION_FAILED, WrapperUnregistrationFailed, 77) \ + V(WRAPPER_RESTORATION_FAILED, WrapperRestorationFailed, 78) \ + /* Filter operations (90-99) */ \ + V(FILTER_NOT_FOUND, FilterNotFound, 90) \ + V(FILTER_FAILED, FilterFailed, 91) \ + /* Cast/conversion operations (100-109) */ \ + V(CAST_FAILED, CastFailed, 100) \ + V(CAST_NOT_SUPPORTED, CastNotSupported, 101) \ + V(MAKE_SEEKABLE_FAILED, MakeSeekableFailed, 102) \ + V(BUFFERED_DATA_LOST, BufferedDataLost, 103) \ + /* Network/socket operations (110-129) */ \ + V(NETWORK_SEND_FAILED, NetworkSendFailed, 110) \ + V(NETWORK_RECV_FAILED, NetworkRecvFailed, 111) \ + V(SSL_NOT_SUPPORTED, SslNotSupported, 112) \ + V(RESUMPTION_FAILED, ResumptionFailed, 113) \ + V(SOCKET_PATH_TOO_LONG, SocketPathTooLong, 114) \ + V(OOB_NOT_SUPPORTED, OobNotSupported, 115) \ + V(PROTOCOL_ERROR, ProtocolError, 116) \ + V(INVALID_URL, InvalidUrl, 117) \ + V(INVALID_RESPONSE, InvalidResponse, 118) \ + V(INVALID_HEADER, InvalidHeader, 119) \ + V(INVALID_PARAM, InvalidParam, 120) \ + V(REDIRECT_LIMIT, RedirectLimit, 121) \ + V(AUTH_FAILED, AuthFailed, 122) \ + /* Encoding/decoding/archiving operations (130-139) */ \ + V(ARCHIVING_FAILED, ArchivingFailed, 130) \ + V(ENCODING_FAILED, EncodingFailed, 131) \ + V(DECODING_FAILED, DecodingFailed, 132) \ + V(INVALID_FORMAT, InvalidFormat, 133) \ + /* Resource/allocation operations (140-149) */ \ + V(ALLOCATION_FAILED, AllocationFailed, 140) \ + V(TEMPORARY_FILE_FAILED, TemporaryFileFailed, 141) \ + /* Locking operations (150-159) */ \ + V(LOCK_FAILED, LockFailed, 150) \ + V(LOCK_NOT_SUPPORTED, LockNotSupported, 151) \ + /* Userspace stream operations (160-169) */ \ + V(USERSPACE_NOT_IMPLEMENTED, UserspaceNotImplemented, 160) \ + V(USERSPACE_INVALID_RETURN, UserspaceInvalidReturn, 161) \ + V(USERSPACE_CALL_FAILED, UserspaceCallFailed, 162) + +/* Generate C enum for internal use */ +typedef enum _StreamErrorCode { +#define V(uc_name, name, val) STREAM_ERROR_CODE_##uc_name = val, + PHP_STREAM_ERROR_CODES(V) +#undef V +} StreamErrorCode; /* Wrapper name for PHP errors */ #define PHP_STREAM_ERROR_WRAPPER_DEFAULT_NAME ":na" #define PHP_STREAM_ERROR_WRAPPER_NAME(_wrapper) \ - (_wrapper ? _wrapper->wops->label : PHP_STREAM_ERROR_WRAPPER_DEFAULT_NAME) - -/* Stored error entry */ -typedef struct { - zend_string *message; - int code; - char *wrapper_name; - char *docref; - char *param; - int severity; - bool terminal; - bool persistent; + (_wrapper ? _wrapper->wops->label : PHP_STREAM_ERROR_WRAPPER_DEFAULT_NAME) + +/* Error entry in chain */ +typedef struct _php_stream_error_entry { + zend_string *message; + StreamErrorCode code; + char *wrapper_name; + char *param; + char *docref; + int severity; + bool terminating; + struct _php_stream_error_entry *next; } php_stream_error_entry; -/* Main error reporting functions */ +/* Active error operation */ +typedef struct _php_stream_error_operation { + php_stream_error_entry *first_error; + php_stream_error_entry *last_error; + uint32_t error_count; + struct _php_stream_error_operation *parent; +} php_stream_error_operation; + +/* Stored completed operation */ +typedef struct _php_stream_stored_error { + php_stream_error_entry *first_error; + struct _php_stream_stored_error *next; +} php_stream_stored_error; + +typedef struct { + /* Stack of active operations (LIFO for nesting) */ + php_stream_error_operation *current_operation; + uint32_t operation_depth; + /* List of completed/stored operations (most recent first) */ + php_stream_stored_error *stored_errors; + uint32_t stored_count; +} php_stream_error_state; + +/* Error operation management */ +PHPAPI php_stream_error_operation *php_stream_error_operation_begin(php_stream_context *context); +PHPAPI void php_stream_error_operation_end(php_stream_context *context); +PHPAPI void php_stream_error_operation_abort(void); + +/* State cleanup function */ +PHPAPI void php_stream_error_state_cleanup(void); + +/* Error object creation */ +PHPAPI void php_stream_error_create_object(zval *zv, php_stream_error_entry *entry); + +/* Wrapper error reporting functions */ PHPAPI void php_stream_wrapper_error_with_name(const char *wrapper_name, - php_stream_context *context, const char *docref, int options, int severity, bool terminal, - int code, const char *fmt, ...) ZEND_ATTRIBUTE_FORMAT(printf, 8, 9); + php_stream_context *context, const char *docref, int options, int severity, + bool terminating, int code, const char *fmt, ...) ZEND_ATTRIBUTE_FORMAT(printf, 8, 9); PHPAPI void php_stream_wrapper_error(php_stream_wrapper *wrapper, php_stream_context *context, - const char *docref, int options, int severity, bool terminal, int code, const char *fmt, + const char *docref, int options, int severity, bool terminating, int code, const char *fmt, ...) ZEND_ATTRIBUTE_FORMAT(printf, 8, 9); PHPAPI void php_stream_wrapper_error_param(php_stream_wrapper *wrapper, php_stream_context *context, - const char *docref, int options, int severity, bool terminal, int code, const char *param, - const char *fmt, ...) ZEND_ATTRIBUTE_FORMAT(printf, 9, 10); + const char *docref, int options, int severity, bool terminating, int code, + const char *param, const char *fmt, ...) ZEND_ATTRIBUTE_FORMAT(printf, 9, 10); PHPAPI void php_stream_wrapper_error_param2(php_stream_wrapper *wrapper, - php_stream_context *context, const char *docref, int options, int severity, bool terminal, - int code, const char *param1, const char *param2, const char *fmt, ...) - ZEND_ATTRIBUTE_FORMAT(printf, 10, 11); + php_stream_context *context, const char *docref, int options, int severity, + bool terminating, int code, const char *param1, const char *param2, const char *fmt, ...) + ZEND_ATTRIBUTE_FORMAT(printf, 10, 11); -PHPAPI void php_stream_error(php_stream *stream, const char *docref, int severity, bool terminal, - int code, const char *fmt, ...) ZEND_ATTRIBUTE_FORMAT(printf, 6, 7); +PHPAPI void php_stream_error(php_stream *stream, const char *docref, int severity, bool terminating, + int code, const char *fmt, ...) ZEND_ATTRIBUTE_FORMAT(printf, 6, 7); -/* Legacy wrapper error log - updated API */ +/* Legacy wrapper error log functions */ PHPAPI void php_stream_wrapper_log_error(const php_stream_wrapper *wrapper, - php_stream_context *context, int options, int severity, bool terminal, int code, + php_stream_context *context, int options, int severity, bool terminating, int code, const char *fmt, ...) ZEND_ATTRIBUTE_FORMAT(printf, 7, 8); PHPAPI void php_stream_wrapper_log_error_param(const php_stream_wrapper *wrapper, - php_stream_context *context, int options, int severity, bool terminal, int code, + php_stream_context *context, int options, int severity, bool terminating, int code, const char *param, const char *fmt, ...) ZEND_ATTRIBUTE_FORMAT(printf, 8, 9); PHPAPI void php_stream_display_wrapper_name_errors(const char *wrapper_name, - php_stream_context *context, int code, const char *path, const char *caption); + php_stream_context *context, int code, const char *path, const char *caption); PHPAPI void php_stream_display_wrapper_errors(php_stream_wrapper *wrapper, - php_stream_context *context, int code, const char *path, const char *caption); + php_stream_context *context, int code, const char *path, const char *caption); PHPAPI void php_stream_tidy_wrapper_name_error_log(const char *wrapper_name); - PHPAPI void php_stream_tidy_wrapper_error_log(php_stream_wrapper *wrapper); /* Convenience macros */ #define php_stream_wrapper_warn(wrapper, context, options, code, ...) \ - php_stream_wrapper_error(wrapper, context, NULL, options, E_WARNING, true, code, __VA_ARGS__) + php_stream_wrapper_error(wrapper, context, NULL, options, E_WARNING, true, code, __VA_ARGS__) #define php_stream_wrapper_warn_name(wrapper_name, context, options, code, ...) \ - php_stream_wrapper_error_with_name(wrapper_name, context, NULL, options, E_WARNING, true, code, __VA_ARGS__) + php_stream_wrapper_error_with_name( \ + wrapper_name, context, NULL, options, E_WARNING, true, code, __VA_ARGS__) #define php_stream_wrapper_warn_nt(wrapper, context, options, code, ...) \ - php_stream_wrapper_error(wrapper, context, NULL, options, E_WARNING, false, code, __VA_ARGS__) + php_stream_wrapper_error(wrapper, context, NULL, options, E_WARNING, false, code, __VA_ARGS__) #define php_stream_wrapper_notice(wrapper, context, options, code, ...) \ - php_stream_wrapper_error(wrapper, context, NULL, options, E_NOTICE, false, code, __VA_ARGS__) + php_stream_wrapper_error(wrapper, context, NULL, options, E_NOTICE, false, code, __VA_ARGS__) #define php_stream_wrapper_warn_param(wrapper, context, options, code, param, ...) \ - php_stream_wrapper_error_param(wrapper, context, NULL, options, E_WARNING, true, code, param, __VA_ARGS__) + php_stream_wrapper_error_param( \ + wrapper, context, NULL, options, E_WARNING, true, code, param, __VA_ARGS__) #define php_stream_wrapper_warn_param_nt(wrapper, context, options, code, param, ...) \ - php_stream_wrapper_error_param(wrapper, context, NULL, options, E_WARNING, false, code, param, __VA_ARGS__) + php_stream_wrapper_error_param( \ + wrapper, context, NULL, options, E_WARNING, false, code, param, __VA_ARGS__) #define php_stream_wrapper_warn_param2(wrapper, context, options, code, param1, param2, ...) \ - php_stream_wrapper_error_param2(wrapper, context, NULL, options, E_WARNING, true, code, param1, param2, __VA_ARGS__) + php_stream_wrapper_error_param2( \ + wrapper, context, NULL, options, E_WARNING, true, code, param1, param2, __VA_ARGS__) #define php_stream_wrapper_warn_param2_nt(wrapper, context, options, code, param1, param2, ...) \ - php_stream_wrapper_error_param2(wrapper, context, NULL, options, E_WARNING, false, code, param1, param2, __VA_ARGS__) + php_stream_wrapper_error_param2( \ + wrapper, context, NULL, options, E_WARNING, false, code, param1, param2, __VA_ARGS__) #define php_stream_warn(stream, code, ...) \ - php_stream_error(stream, NULL, E_WARNING, true, code, __VA_ARGS__) + php_stream_error(stream, NULL, E_WARNING, true, code, __VA_ARGS__) #define php_stream_warn_nt(stream, code, ...) \ - php_stream_error(stream, NULL, E_WARNING, false, code, __VA_ARGS__) + php_stream_error(stream, NULL, E_WARNING, false, code, __VA_ARGS__) #define php_stream_warn_docref(stream, docref, code, ...) \ - php_stream_error(stream, docref, E_WARNING, true, code, __VA_ARGS__) + php_stream_error(stream, docref, E_WARNING, true, code, __VA_ARGS__) #define php_stream_notice(stream, code, ...) \ - php_stream_error(stream, NULL, E_NOTICE, false, code, __VA_ARGS__) + php_stream_error(stream, NULL, E_NOTICE, false, code, __VA_ARGS__) #define php_stream_fatal(stream, code, ...) \ - php_stream_error(stream, NULL, E_ERROR, true, code, __VA_ARGS__) + php_stream_error(stream, NULL, E_ERROR, true, code, __VA_ARGS__) /* Legacy log variants */ #define php_stream_wrapper_log_warn(wrapper, context, options, code, ...) \ - php_stream_wrapper_log_error(wrapper, context, options, E_WARNING, true, code, __VA_ARGS__) + php_stream_wrapper_log_error(wrapper, context, options, E_WARNING, true, code, __VA_ARGS__) #define php_stream_wrapper_log_warn_nt(wrapper, context, options, code, ...) \ - php_stream_wrapper_log_error(wrapper, context, options, E_WARNING, false, code, __VA_ARGS__) + php_stream_wrapper_log_error(wrapper, context, options, E_WARNING, false, code, __VA_ARGS__) #define php_stream_wrapper_log_notice(wrapper, context, options, code, ...) \ - php_stream_wrapper_log_error(wrapper, context, options, E_NOTICE, false, code, __VA_ARGS__) + php_stream_wrapper_log_error(wrapper, context, options, E_NOTICE, false, code, __VA_ARGS__) END_EXTERN_C() diff --git a/main/streams/stream_errors.c b/main/streams/stream_errors.c index 0a199589370ae..5e17f6aa49146 100644 --- a/main/streams/stream_errors.c +++ b/main/streams/stream_errors.c @@ -18,31 +18,28 @@ #include "php_globals.h" #include "php_streams.h" #include "php_stream_errors.h" -#include "stream_errors_arginfo.h" +#include "zend_enum.h" #include "zend_exceptions.h" #include "ext/standard/file.h" +#include "stream_errors_arginfo.h" -/* StreamException class entry */ +/* Class entries */ +static zend_class_entry *php_ce_stream_error_code; +static zend_class_entry *php_ce_stream_error_mode; +static zend_class_entry *php_ce_stream_error_store; +static zend_class_entry *php_ce_stream_error; static zend_class_entry *php_ce_stream_exception; -static void php_stream_error_entry_dtor(void *error) -{ - php_stream_error_entry *entry = *(php_stream_error_entry **) error; - zend_string_release(entry->message); - pefree(entry->wrapper_name, entry->persistent); - pefree(entry->docref, entry->persistent); - // param is not currently supported for streams so cannot be persistent - ZEND_ASSERT(!entry->persistent || entry->param == NULL); - efree(entry->param); - pefree(entry, entry->persistent); -} +/* Lookup table for error code to case name */ +static const char *const php_stream_error_code_names[200] = { +#define V(uc_name, name, val) [val] = #name, + PHP_STREAM_ERROR_CODES(V) +#undef V +}; -static void php_stream_error_list_dtor(zval *item) -{ - zend_llist *list = (zend_llist *) Z_PTR_P(item); - zend_llist_destroy(list); - efree(list); -} +/* Forward declarations */ +static void php_stream_error_entry_free(php_stream_error_entry *entry); +static bool php_stream_error_code_in_range(zval *this_zv, int start, int end); /* Context option helpers */ @@ -67,8 +64,25 @@ static int php_stream_get_error_mode(php_stream_context *context) } zval *option = php_stream_context_get_option(context, "stream", "error_mode"); - if (option && Z_TYPE_P(option) == IS_LONG) { - return Z_LVAL_P(option); + if (!option) { + return PHP_STREAM_ERROR_MODE_ERROR; + } + + if (Z_TYPE_P(option) != IS_OBJECT + || !instanceof_function(Z_OBJCE_P(option), php_ce_stream_error_mode)) { + zend_type_error("stream context option 'error_mode' must be of type StreamErrorMode"); + return PHP_STREAM_ERROR_MODE_ERROR; + } + + /* Get enum case name */ + zend_string *case_name = Z_STR_P(zend_enum_fetch_case_name(Z_OBJ_P(option))); + + if (zend_string_equals_literal(case_name, "Error")) { + return PHP_STREAM_ERROR_MODE_ERROR; + } else if (zend_string_equals_literal(case_name, "Exception")) { + return PHP_STREAM_ERROR_MODE_EXCEPTION; + } else if (zend_string_equals_literal(case_name, "Silent")) { + return PHP_STREAM_ERROR_MODE_SILENT; } return PHP_STREAM_ERROR_MODE_ERROR; @@ -81,540 +95,978 @@ static int php_stream_get_error_store_mode(php_stream_context *context, int erro } zval *option = php_stream_context_get_option(context, "stream", "error_store"); - if (option && Z_TYPE_P(option) == IS_LONG) { - int store_mode = Z_LVAL_P(option); + if (!option) { + return php_stream_auto_decide_error_store_mode(error_mode); + } - if (store_mode == PHP_STREAM_ERROR_STORE_AUTO) { - return php_stream_auto_decide_error_store_mode(error_mode); - } + if (Z_TYPE_P(option) != IS_OBJECT + || !instanceof_function(Z_OBJCE_P(option), php_ce_stream_error_store)) { + zend_type_error("stream context option 'error_store' must be of type StreamErrorStore"); + return php_stream_auto_decide_error_store_mode(error_mode); + } + + /* Get enum case name */ + zend_string *case_name = Z_STR_P(zend_enum_fetch_case_name(Z_OBJ_P(option))); - return store_mode; + if (zend_string_equals_literal(case_name, "Auto")) { + return php_stream_auto_decide_error_store_mode(error_mode); + } else if (zend_string_equals_literal(case_name, "None")) { + return PHP_STREAM_ERROR_STORE_NONE; + } else if (zend_string_equals_literal(case_name, "NonTerminal")) { + return PHP_STREAM_ERROR_STORE_NON_TERM; + } else if (zend_string_equals_literal(case_name, "Terminal")) { + return PHP_STREAM_ERROR_STORE_TERMINAL; + } else if (zend_string_equals_literal(case_name, "All")) { + return PHP_STREAM_ERROR_STORE_ALL; } return php_stream_auto_decide_error_store_mode(error_mode); } -static bool php_stream_should_store_error(int store_mode, bool terminal) +/* Helper functions */ + +static bool php_stream_has_terminating_error(php_stream_error_operation *op) { - switch (store_mode) { - case PHP_STREAM_ERROR_STORE_NONE: - return false; - case PHP_STREAM_ERROR_STORE_NON_TERM: - return !terminal; - case PHP_STREAM_ERROR_STORE_TERMINAL: - return terminal; - case PHP_STREAM_ERROR_STORE_ALL: + php_stream_error_entry *entry = op->first_error; + while (entry) { + if (entry->terminating) { return true; - default: - return false; + } + entry = entry->next; } + return false; } -/* StreamException methods */ +static void php_stream_error_entry_free(php_stream_error_entry *entry) +{ + while (entry) { + php_stream_error_entry *next = entry->next; + zend_string_release(entry->message); + efree(entry->wrapper_name); + efree(entry->param); + efree(entry); + entry = next; + } +} -static void php_stream_throw_exception( - const char *message, int code, const char *wrapper_name, const char *param) +static void php_stream_error_operation_free(php_stream_error_operation *op) { - zval ex; + php_stream_error_entry_free(op->first_error); + efree(op); +} - object_init_ex(&ex, php_ce_stream_exception); +/* Cleanup function for request shutdown */ +PHPAPI void php_stream_error_state_cleanup(void) +{ + /* Clear active operations (shouldn't normally have any, but clean up just in case) */ + while (FG(stream_error_state).current_operation) { + php_stream_error_operation *op = FG(stream_error_state).current_operation; + FG(stream_error_state).current_operation = op->parent; + php_stream_error_operation_free(op); + } + + /* Clear stored errors */ + php_stream_stored_error *stored = FG(stream_error_state).stored_errors; + while (stored) { + php_stream_stored_error *next = stored->next; + php_stream_error_entry_free(stored->first_error); + efree(stored); + stored = next; + } + + FG(stream_error_state).stored_errors = NULL; + FG(stream_error_state).stored_count = 0; + FG(stream_error_state).operation_depth = 0; +} - zend_update_property_string(php_ce_stream_exception, Z_OBJ(ex), ZEND_STRL("message"), message); - zend_update_property_long(php_ce_stream_exception, Z_OBJ(ex), ZEND_STRL("code"), code); - zend_update_property_string( - php_ce_stream_exception, Z_OBJ(ex), ZEND_STRL("wrapperName"), wrapper_name); +/* Error operation stack management */ - if (param) { - zend_update_property_string(php_ce_stream_exception, Z_OBJ(ex), ZEND_STRL("param"), param); +PHPAPI php_stream_error_operation *php_stream_error_operation_begin(php_stream_context *context) +{ + /* Check depth limit */ + if (FG(stream_error_state).operation_depth >= PHP_STREAM_ERROR_MAX_DEPTH) { + php_error_docref(NULL, E_WARNING, + "Stream error operation depth exceeded (%u), possible infinite recursion", + FG(stream_error_state).operation_depth); + return NULL; } - zend_throw_exception_object(&ex); + /* Create new operation with empty error list */ + php_stream_error_operation *op = emalloc(sizeof(php_stream_error_operation)); + op->first_error = NULL; + op->last_error = NULL; + op->error_count = 0; + op->parent = FG(stream_error_state).current_operation; + + /* Push onto stack */ + FG(stream_error_state).current_operation = op; + FG(stream_error_state).operation_depth++; + + return op; +} + +static void php_stream_error_add(StreamErrorCode code, const char *wrapper_name, + const char *message, const char *docref, const char *param, int severity, + bool terminating) +{ + php_stream_error_operation *op = FG(stream_error_state).current_operation; + + if (!op) { + /* No operation context - skip */ + return; + } + + php_stream_error_entry *entry = emalloc(sizeof(php_stream_error_entry)); + entry->message = zend_string_init(message, strlen(message), 0); + entry->code = code; + entry->wrapper_name = wrapper_name ? estrdup(wrapper_name) : NULL; + entry->param = param ? estrdup(param) : NULL; + entry->param = docref ? estrdup(docref) : NULL; + entry->severity = severity; + entry->terminating = terminating; + entry->next = NULL; + + /* Append to operation's error list */ + if (op->last_error) { + op->last_error->next = entry; + } else { + op->first_error = entry; + } + op->last_error = entry; + op->error_count++; } -/* Core error processing */ +/* Error reporting */ + +static void php_stream_call_error_handler(zval *handler, zval *error_obj) +{ + zend_fcall_info_cache fcc; + char *is_callable_error = NULL; + + if (!zend_is_callable_ex(handler, NULL, 0, NULL, &fcc, &is_callable_error)) { + if (is_callable_error) { + zend_type_error("stream error handler must be a valid callback, %s", is_callable_error); + efree(is_callable_error); + } + return; + } + + zval retval; -static void php_stream_process_error(php_stream_context *context, const char *wrapper_name, - php_stream *stream, const char *docref, int code, const char *message, const char *param, - int severity, bool terminal) + call_user_function(NULL, NULL, handler, &retval, 1, error_obj); + + zval_ptr_dtor(&retval); +} + +static void php_stream_throw_exception_with_errors(php_stream_error_operation *op) { - int error_mode = php_stream_get_error_mode(context); + if (!op->first_error) { + return; + } + + /* Create StreamError object from error chain */ + zval error_obj; + php_stream_error_create_object(&error_obj, op->first_error); + + /* Create exception */ + zval ex; + object_init_ex(&ex, php_ce_stream_exception); + + /* Set message from first error */ + zend_update_property_string(php_ce_stream_exception, Z_OBJ(ex), ZEND_STRL("message"), + ZSTR_VAL(op->first_error->message)); + + /* Set code from first error enum value */ + zend_update_property_long(php_ce_stream_exception, Z_OBJ(ex), ZEND_STRL("code"), + (zend_long) op->first_error->code); + + /* Set the complete error object */ + zend_update_property(php_ce_stream_exception, Z_OBJ(ex), ZEND_STRL("error"), &error_obj); + + zval_ptr_dtor(&error_obj); + zend_throw_exception_object(&ex); +} - /* Handle error based on error_mode */ +static void php_stream_report_errors(php_stream_context *context, php_stream_error_operation *op, + int error_mode, bool is_terminating) +{ switch (error_mode) { - case PHP_STREAM_ERROR_MODE_ERROR: - if (param) { - php_error_docref1(docref, param, severity, "%s", message); - } else { - php_error_docref(docref, severity, "%s", message); + case PHP_STREAM_ERROR_MODE_ERROR: { + /* Report all errors individually */ + php_stream_error_entry *entry = op->first_error; + while (entry) { + if (entry->param) { + php_error_docref1( + entry->docref, entry->param, entry->severity, "%s", ZSTR_VAL(entry->message)); + } else { + php_error_docref(entry->docref, entry->severity, "%s", ZSTR_VAL(entry->message)); + } + entry = entry->next; } break; + } - case PHP_STREAM_ERROR_MODE_EXCEPTION: - if (terminal) { - php_stream_throw_exception(message, code, wrapper_name, param); + case PHP_STREAM_ERROR_MODE_EXCEPTION: { + if (is_terminating) { + php_stream_throw_exception_with_errors(op); } break; + } case PHP_STREAM_ERROR_MODE_SILENT: + /* Don't report */ break; } /* Call user error handler if set */ - if (context) { - zval *handler = php_stream_context_get_option(context, "stream", "error_handler"); - if (handler) { - zend_fcall_info_cache fcc; - char *is_callable_error = NULL; - zval retval; - zval args[5]; - - if (!zend_is_callable_ex(handler, NULL, 0, NULL, &fcc, &is_callable_error)) { - if (is_callable_error) { - zend_type_error( - "stream error handler must be a valid callback, %s", is_callable_error); - efree(is_callable_error); - } else { - zend_type_error("stream error must be a valid callback"); - } - return; - } + zval *handler + = context ? php_stream_context_get_option(context, "stream", "error_handler") : NULL; - /* Arg 0: wrapper name */ - ZVAL_STRING(&args[0], wrapper_name); + if (handler) { + /* Create StreamError object from error chain */ + zval error_obj; + php_stream_error_create_object(&error_obj, op->first_error); - /* Arg 1: stream resource or null */ - if (stream && stream->res) { - ZVAL_RES(&args[1], stream->res); - GC_ADDREF(stream->res); - } else { - ZVAL_NULL(&args[1]); - } + /* Call handler(error) */ + php_stream_call_error_handler(handler, &error_obj); + + zval_ptr_dtor(&error_obj); + } +} + +/* Error storage - move and filter */ - /* Arg 2: error code */ - ZVAL_LONG(&args[2], code); +PHPAPI void php_stream_error_operation_end(php_stream_context *context) +{ + php_stream_error_operation *op = FG(stream_error_state).current_operation; + + if (!op) { + return; + } - /* Arg 3: message */ - ZVAL_STRING(&args[3], message); + /* Pop from stack */ + FG(stream_error_state).current_operation = op->parent; + FG(stream_error_state).operation_depth--; - /* Arg 4: param (or null) */ - if (param) { - ZVAL_STRING(&args[4], param); - } else { - ZVAL_NULL(&args[4]); + /* Process errors if we have any */ + if (op->error_count > 0) { + /* Get error handling settings */ + int error_mode = php_stream_get_error_mode(context); + int store_mode = php_stream_get_error_store_mode(context, error_mode); + + bool is_terminating = php_stream_has_terminating_error(op); + + /* Always report errors */ + php_stream_report_errors(context, op, error_mode, is_terminating); + + /* Handle storage */ + if (store_mode == PHP_STREAM_ERROR_STORE_NONE) { + /* Free all errors */ + php_stream_error_entry_free(op->first_error); + op->first_error = NULL; + op->last_error = NULL; + } else { + /* Filter and store */ + php_stream_error_entry *entry = op->first_error; + php_stream_error_entry *prev = NULL; + php_stream_error_entry *to_store_first = NULL; + php_stream_error_entry *to_store_last = NULL; + + while (entry) { + php_stream_error_entry *next = entry->next; + bool should_store = false; + + if (store_mode == PHP_STREAM_ERROR_STORE_ALL) { + should_store = true; + } else if (store_mode == PHP_STREAM_ERROR_STORE_NON_TERM && !entry->terminating) { + should_store = true; + } else if (store_mode == PHP_STREAM_ERROR_STORE_TERMINAL && entry->terminating) { + should_store = true; + } + + if (should_store) { + /* Move to storage chain */ + if (prev) { + prev->next = next; + } else { + op->first_error = next; + } + + entry->next = NULL; + if (to_store_last) { + to_store_last->next = entry; + } else { + to_store_first = entry; + } + to_store_last = entry; + } else { + /* Free this error */ + if (prev) { + prev->next = next; + } else { + op->first_error = next; + } + + zend_string_release(entry->message); + efree(entry->wrapper_name); + efree(entry->param); + efree(entry); + + /* Don't update prev */ + entry = next; + continue; + } + + prev = entry; + entry = next; } - call_user_function(NULL, NULL, handler, &retval, 5, args); + /* Store filtered errors if any */ + if (to_store_first) { + php_stream_stored_error *stored = emalloc(sizeof(php_stream_stored_error)); + stored->first_error = to_store_first; + stored->next = FG(stream_error_state).stored_errors; + + FG(stream_error_state).stored_errors = stored; + FG(stream_error_state).stored_count++; + } - zval_ptr_dtor(&retval); - zval_ptr_dtor(&args[0]); - zval_ptr_dtor(&args[1]); - zval_ptr_dtor(&args[3]); - zval_ptr_dtor(&args[4]); + /* Free any remaining errors not moved to storage */ + php_stream_error_entry_free(op->first_error); + op->first_error = NULL; + op->last_error = NULL; } } + + /* Free operation structure */ + efree(op); } -/* Helper to create error entry */ -static php_stream_error_entry *php_stream_create_error_entry(zend_string *message, int code, - const char *wrapper_name, const char *docref, char *param, int severity, bool terminal, - bool persistent) +PHPAPI void php_stream_error_operation_abort(void) { - if (persistent) { - message = zend_string_dup(message, true); - } else { - zend_string_addref(message); + php_stream_error_operation *op = FG(stream_error_state).current_operation; + + if (!op) { + return; } - php_stream_error_entry *entry = pemalloc(sizeof(php_stream_error_entry), persistent); - entry->message = message; - entry->code = code; - entry->wrapper_name = wrapper_name ? pestrdup(wrapper_name, persistent) : NULL; - entry->docref = docref ? pestrdup(docref, persistent) : NULL; - entry->param = param; - entry->severity = severity; - entry->terminal = terminal; - entry->persistent = persistent; + FG(stream_error_state).current_operation = op->parent; + FG(stream_error_state).operation_depth--; - return entry; + php_stream_error_operation_free(op); } -/* Common storage function*/ -static void php_stream_store_error_common(php_stream_context *context, php_stream *stream, - zend_string *message, const char *docref, int code, const char *wrapper_name, char *param, - int severity, bool terminal) -{ - int error_mode = php_stream_get_error_mode(context); - int store_mode = php_stream_get_error_store_mode(context, error_mode); +/* Wrapper error reporting */ - if (!php_stream_should_store_error(store_mode, terminal)) { - efree(param); - return; +static void php_stream_wrapper_error_internal(const char *wrapper_name, php_stream_context *context, + const char *docref, int options, int severity, bool terminating, int code, char *param, + const char *message) +{ + /* If not in an operation, create one */ + bool implicit_operation = (FG(stream_error_state).current_operation == NULL); + if (implicit_operation) { + php_stream_error_operation_begin(context); } - zend_llist *list; - bool persistent = false; - if (stream) { - persistent = stream->is_persistent; - /* Store in stream's error list */ - if (!stream->error_list) { - stream->error_list = pemalloc(sizeof(zend_llist), persistent); - zend_llist_init(stream->error_list, sizeof(php_stream_error_entry *), - php_stream_error_entry_dtor, persistent); - } - list = stream->error_list; - } else { - /* Store in FG(stream_errors) for wrapper errors */ - if (!FG(wrapper_stored_errors)) { - ALLOC_HASHTABLE(FG(wrapper_stored_errors)); - zend_hash_init(FG(wrapper_stored_errors), 8, NULL, php_stream_error_list_dtor, 0); - list = NULL; - } else { - list = zend_hash_str_find_ptr( - FG(wrapper_stored_errors), wrapper_name, strlen(wrapper_name)); - } + /* Add to current operation (or skip if no operation) */ + php_stream_error_add(code, wrapper_name, message, docref, param, severity, terminating); - if (!list) { - zend_llist new_list; - zend_llist_init( - &new_list, sizeof(php_stream_error_entry *), php_stream_error_entry_dtor, 0); - list = zend_hash_str_update_mem(FG(wrapper_stored_errors), wrapper_name, - strlen(wrapper_name), &new_list, sizeof(new_list)); - } + /* If we created implicit operation, end it immediately */ + if (implicit_operation) { + php_stream_error_operation_end(context); } +} - php_stream_error_entry *entry = php_stream_create_error_entry( - message, code, wrapper_name, docref, param, severity, terminal, persistent); +PHPAPI void php_stream_wrapper_error_with_name(const char *wrapper_name, + php_stream_context *context, const char *docref, int options, int severity, + bool terminating, int code, const char *fmt, ...) +{ + if (!(options & REPORT_ERRORS)) { + return; + } + + va_list args; + va_start(args, fmt); + + char *message = NULL; + vspprintf(&message, 0, fmt, args); + va_end(args); + + php_stream_wrapper_error_internal( + wrapper_name, context, docref, options, severity, terminating, code, NULL, message); + + efree(message); +} - zend_llist_add_element(list, &entry); +PHPAPI void php_stream_wrapper_error(php_stream_wrapper *wrapper, + php_stream_context *context, const char *docref, int options, + int severity, bool terminating, int code, const char *fmt, ...) +{ + if (!(options & REPORT_ERRORS)) { + return; + } + + va_list args; + va_start(args, fmt); + + char *message = NULL; + vspprintf(&message, 0, fmt, args); + va_end(args); + + const char *wrapper_name = PHP_STREAM_ERROR_WRAPPER_NAME(wrapper); + + php_stream_wrapper_error_internal( + wrapper_name, context, docref, options, severity, terminating, code, NULL, message); + + efree(message); } -/* Wrapper error reporting - stores in FG(wrapper_stored_errors) */ -static void php_stream_wrapper_error_internal_with_name_and_message(const char *wrapper_name, - php_stream_context *context, const char *docref, int options, int severity, bool terminal, - int code, char *param, zend_string *message) +PHPAPI void php_stream_wrapper_error_param(php_stream_wrapper *wrapper, + php_stream_context *context, const char *docref, int options, + int severity, bool terminating, int code, const char *param, + const char *fmt, ...) { - php_stream_process_error(context, wrapper_name, NULL, docref, code, ZSTR_VAL(message), param, - severity, terminal); + if (!(options & REPORT_ERRORS)) { + return; + } + + va_list args; + va_start(args, fmt); + + char *message = NULL; + vspprintf(&message, 0, fmt, args); + va_end(args); + + const char *wrapper_name = PHP_STREAM_ERROR_WRAPPER_NAME(wrapper); + char *param_copy = param ? estrdup(param) : NULL; + + php_stream_wrapper_error_internal( + wrapper_name, context, docref, options, severity, terminating, code, param_copy, message); + + efree(message); +} - php_stream_store_error_common( - context, NULL, message, docref, code, wrapper_name, param, severity, terminal); +PHPAPI void php_stream_wrapper_error_param2(php_stream_wrapper *wrapper, + php_stream_context *context, const char *docref, int options, + int severity, bool terminating, int code, const char *param1, + const char *param2, const char *fmt, ...) +{ + if (!(options & REPORT_ERRORS)) { + return; + } + + char *combined_param; + spprintf(&combined_param, 0, "%s,%s", param1, param2); + + va_list args; + va_start(args, fmt); + + char *message = NULL; + vspprintf(&message, 0, fmt, args); + va_end(args); + + const char *wrapper_name = PHP_STREAM_ERROR_WRAPPER_NAME(wrapper); + + php_stream_wrapper_error_internal( + wrapper_name, context, docref, options, severity, terminating, code, combined_param, message); + + efree(message); } -static void php_stream_wrapper_error_internal_with_name(const char *wrapper_name, - php_stream_context *context, const char *docref, int options, int severity, bool terminal, - int code, char *param, const char *fmt, va_list args) +/* Stream error reporting - delegates to wrapper errors */ + +PHPAPI void php_stream_error(php_stream *stream, const char *docref, + int severity, bool terminating, int code, const char *fmt, ...) { - zend_string *message = vstrpprintf(0, fmt, args); + va_list args; + va_start(args, fmt); + + char *message = NULL; + vspprintf(&message, 0, fmt, args); + va_end(args); + + const char *wrapper_name = stream->wrapper + ? stream->wrapper->wops->label + : "stream"; + + php_stream_context *context = PHP_STREAM_CONTEXT(stream); + + /* Just call the wrapper error function */ + php_stream_wrapper_error_internal( + wrapper_name, + context, + docref, + REPORT_ERRORS, + severity, + terminating, + code, + NULL, + message + ); + + efree(message); +} - php_stream_wrapper_error_internal_with_name_and_message( - wrapper_name, context, docref, options, severity, terminal, code, param, message); +/* Legacy wrapper error logging */ - zend_string_release(message); +static void php_stream_error_entry_dtor_legacy(void *error) +{ + php_stream_error_entry *entry = *(php_stream_error_entry **) error; + zend_string_release(entry->message); + efree(entry->wrapper_name); + efree(entry->param); + efree(entry->docref); + efree(entry); } -static void php_stream_wrapper_error_internal_with_name_variadic(const char *wrapper_name, - php_stream_context *context, const char *docref, int options, int severity, bool terminal, - int code, char *param, const char *fmt, ...) +static void php_stream_error_list_dtor(zval *item) { - va_list args; - va_start(args, fmt); + zend_llist *list = (zend_llist *) Z_PTR_P(item); + zend_llist_destroy(list); + efree(list); +} - php_stream_wrapper_error_internal_with_name( - wrapper_name, context, docref, options, severity, terminal, code, param, fmt, args); +static void php_stream_wrapper_log_store_error(zend_string *message, int code, + const char *wrapper_name, const char *param, int severity, bool terminating) +{ + char *param_copy = param ? estrdup(param) : NULL; + + php_stream_error_entry *entry = emalloc(sizeof(php_stream_error_entry)); + entry->message = zend_string_copy(message); + entry->code = code; + entry->wrapper_name = wrapper_name ? estrdup(wrapper_name) : NULL; + entry->param = param_copy; + entry->severity = severity; + entry->terminating = terminating; + entry->next = NULL; + + if (!FG(wrapper_logged_errors)) { + ALLOC_HASHTABLE(FG(wrapper_logged_errors)); + zend_hash_init(FG(wrapper_logged_errors), 8, NULL, php_stream_error_list_dtor, 0); + } + + zend_llist *list = zend_hash_str_find_ptr( + FG(wrapper_logged_errors), wrapper_name, strlen(wrapper_name)); + + if (!list) { + zend_llist new_list; + zend_llist_init(&new_list, sizeof(php_stream_error_entry *), + php_stream_error_entry_dtor_legacy, 0); + list = zend_hash_str_update_mem(FG(wrapper_logged_errors), wrapper_name, + strlen(wrapper_name), &new_list, sizeof(new_list)); + } + + zend_llist_add_element(list, &entry); +} - va_end(args); +static void php_stream_wrapper_log_error_internal(const php_stream_wrapper *wrapper, + php_stream_context *context, int options, int severity, bool terminating, + int code, char *param, const char *fmt, va_list args) +{ + zend_string *message = vstrpprintf(0, fmt, args); + const char *wrapper_name = PHP_STREAM_ERROR_WRAPPER_NAME(wrapper); + + if (options & REPORT_ERRORS) { + /* Report immediately */ + php_stream_wrapper_error_internal( + wrapper_name, context, NULL, options, severity, terminating, code, param, ZSTR_VAL(message)); + } else { + /* Store for later display */ + php_stream_wrapper_log_store_error(message, code, wrapper_name, param, severity, terminating); + } + + zend_string_release(message); } -static void php_stream_wrapper_error_internal(php_stream_wrapper *wrapper, - php_stream_context *context, const char *docref, int options, int severity, bool terminal, - int code, char *param, const char *fmt, va_list args) +PHPAPI void php_stream_wrapper_log_error(const php_stream_wrapper *wrapper, + php_stream_context *context, int options, int severity, bool terminating, + int code, const char *fmt, ...) { - const char *wrapper_name = PHP_STREAM_ERROR_WRAPPER_NAME(wrapper); + va_list args; + va_start(args, fmt); + php_stream_wrapper_log_error_internal( + wrapper, context, options, severity, terminating, code, NULL, fmt, args); + va_end(args); +} - php_stream_wrapper_error_internal_with_name( - wrapper_name, context, docref, options, severity, terminal, code, param, fmt, args); +PHPAPI void php_stream_wrapper_log_error_param(const php_stream_wrapper *wrapper, + php_stream_context *context, int options, int severity, bool terminating, + int code, const char *param, const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + char *param_copy = param ? estrdup(param) : NULL; + php_stream_wrapper_log_error_internal( + wrapper, context, options, severity, terminating, code, param_copy, fmt, args); + va_end(args); } -PHPAPI void php_stream_wrapper_error_with_name(const char *wrapper_name, - php_stream_context *context, const char *docref, int options, int severity, bool terminal, - int code, const char *fmt, ...) +static zend_llist *php_stream_get_wrapper_errors_list(const char *wrapper_name) { - if (options & REPORT_ERRORS) { - va_list args; - va_start(args, fmt); - php_stream_wrapper_error_internal_with_name( - wrapper_name, context, docref, options, severity, terminal, code, NULL, fmt, args); - va_end(args); - } + if (!FG(wrapper_logged_errors)) { + return NULL; + } + return (zend_llist *) zend_hash_str_find_ptr( + FG(wrapper_logged_errors), wrapper_name, strlen(wrapper_name)); } -PHPAPI void php_stream_wrapper_error(php_stream_wrapper *wrapper, php_stream_context *context, - const char *docref, int options, int severity, bool terminal, int code, const char *fmt, - ...) +PHPAPI void php_stream_display_wrapper_name_errors(const char *wrapper_name, + php_stream_context *context, int code, const char *path, const char *caption) { - if (options & REPORT_ERRORS) { - va_list args; - va_start(args, fmt); - php_stream_wrapper_error_internal( - wrapper, context, docref, options, severity, terminal, code, NULL, fmt, args); - va_end(args); - } + char *msg; + char errstr[256]; + int free_msg = 0; + + if (EG(exception)) { + return; + } + + char *tmp = estrdup(path); + if (strcmp(wrapper_name, PHP_STREAM_ERROR_WRAPPER_DEFAULT_NAME)) { + zend_llist *err_list = php_stream_get_wrapper_errors_list(wrapper_name); + if (err_list) { + size_t l = 0; + int brlen; + int i; + int count = (int) zend_llist_count(err_list); + const char *br; + php_stream_error_entry **err_entry_p; + zend_llist_position pos; + + if (PG(html_errors)) { + brlen = 7; + br = "
\n"; + } else { + brlen = 1; + br = "\n"; + } + + for (err_entry_p = zend_llist_get_first_ex(err_list, &pos), i = 0; err_entry_p; + err_entry_p = zend_llist_get_next_ex(err_list, &pos), i++) { + l += ZSTR_LEN((*err_entry_p)->message); + if (i < count - 1) { + l += brlen; + } + } + msg = emalloc(l + 1); + msg[0] = '\0'; + for (err_entry_p = zend_llist_get_first_ex(err_list, &pos), i = 0; err_entry_p; + err_entry_p = zend_llist_get_next_ex(err_list, &pos), i++) { + strcat(msg, ZSTR_VAL((*err_entry_p)->message)); + if (i < count - 1) { + strcat(msg, br); + } + } + + free_msg = 1; + } else { + if (!strcmp(wrapper_name, php_plain_files_wrapper.wops->label)) { + msg = php_socket_strerror_s(errno, errstr, sizeof(errstr)); + } else { + msg = "operation failed"; + } + } + } else { + msg = "no suitable wrapper could be found"; + } + + php_strip_url_passwd(tmp); + + char *full_msg; + spprintf(&full_msg, 0, "%s: %s", caption, msg); + + php_stream_wrapper_error_internal( + wrapper_name, context, NULL, REPORT_ERRORS, E_WARNING, true, code, tmp, full_msg); + + efree(full_msg); + + if (free_msg) { + efree(msg); + } } -PHPAPI void php_stream_wrapper_error_param(php_stream_wrapper *wrapper, php_stream_context *context, - const char *docref, int options, int severity, bool terminal, int code, const char *param, - const char *fmt, ...) +PHPAPI void php_stream_display_wrapper_errors(php_stream_wrapper *wrapper, + php_stream_context *context, int code, const char *path, const char *caption) { - if (options & REPORT_ERRORS) { - va_list args; - va_start(args, fmt); - char *param_copy = param ? estrdup(param) : NULL; - php_stream_wrapper_error_internal( - wrapper, context, docref, options, severity, terminal, code, param_copy, fmt, args); - va_end(args); - } + if (wrapper) { + const char *wrapper_name = PHP_STREAM_ERROR_WRAPPER_NAME(wrapper); + php_stream_display_wrapper_name_errors(wrapper_name, context, code, path, caption); + } } -PHPAPI void php_stream_wrapper_error_param2(php_stream_wrapper *wrapper, - php_stream_context *context, const char *docref, int options, int severity, bool terminal, - int code, const char *param1, const char *param2, const char *fmt, ...) +PHPAPI void php_stream_tidy_wrapper_name_error_log(const char *wrapper_name) { - if (options & REPORT_ERRORS) { - char *combined_param; - spprintf(&combined_param, 0, "%s,%s", param1, param2); + if (FG(wrapper_logged_errors)) { + zend_hash_str_del(FG(wrapper_logged_errors), wrapper_name, strlen(wrapper_name)); + } +} - va_list args; - va_start(args, fmt); - php_stream_wrapper_error_internal(wrapper, context, docref, options, severity, terminal, - code, combined_param, fmt, args); - va_end(args); - } +PHPAPI void php_stream_tidy_wrapper_error_log(php_stream_wrapper *wrapper) +{ + if (wrapper) { + const char *wrapper_name = PHP_STREAM_ERROR_WRAPPER_NAME(wrapper); + php_stream_tidy_wrapper_name_error_log(wrapper_name); + } } -/* Wrapper error logging - stores in FG(wrapper_logged_errors) */ +/* StreamError object creation - no enum cache */ -static void php_stream_wrapper_log_store_error(zend_string *message, int code, - const char *wrapper_name, const char *param, int severity, bool terminal) +PHPAPI void php_stream_error_create_object(zval *zv, php_stream_error_entry *entry) { - char *param_copy = param ? estrdup(param) : NULL; - php_stream_error_entry *entry = php_stream_create_error_entry( - message, code, wrapper_name, NULL, param_copy, severity, terminal, false); - - if (!FG(wrapper_logged_errors)) { - ALLOC_HASHTABLE(FG(wrapper_logged_errors)); - zend_hash_init(FG(wrapper_logged_errors), 8, NULL, php_stream_error_list_dtor, 0); + if (!entry) { + ZVAL_NULL(zv); + return; } - zend_llist *list - = zend_hash_str_find_ptr(FG(wrapper_logged_errors), wrapper_name, strlen(wrapper_name)); + object_init_ex(zv, php_ce_stream_error); + + /* Get enum case by value using lookup array */ + const char *case_name = NULL; + int code_value = (int) entry->code; - if (!list) { - zend_llist new_list; - zend_llist_init( - &new_list, sizeof(php_stream_error_entry *), php_stream_error_entry_dtor, 0); - list = zend_hash_str_update_mem(FG(wrapper_logged_errors), wrapper_name, - strlen(wrapper_name), &new_list, sizeof(new_list)); + if (code_value >= 0 + && code_value < (int) (sizeof(php_stream_error_code_names) + / sizeof(php_stream_error_code_names[0]))) { + case_name = php_stream_error_code_names[code_value]; } - zend_llist_add_element(list, &entry); -} + if (!case_name) { + case_name = "Generic"; + } -static void php_stream_wrapper_log_error_internal(const php_stream_wrapper *wrapper, - php_stream_context *context, int options, int severity, bool terminal, int code, - char *param, const char *fmt, va_list args) -{ - zend_string *message = vstrpprintf(0, fmt, args); - const char *wrapper_name = PHP_STREAM_ERROR_WRAPPER_NAME(wrapper); + zend_object *enum_obj = zend_enum_get_case_cstr(php_ce_stream_error_code, case_name); + ZEND_ASSERT(enum_obj != NULL); + + zval code_enum; + ZVAL_OBJ(&code_enum, enum_obj); + GC_ADDREF(enum_obj); + + zend_update_property(php_ce_stream_error, Z_OBJ_P(zv), ZEND_STRL("code"), &code_enum); + zval_ptr_dtor(&code_enum); + + /* Set other properties */ + zend_update_property_str( + php_ce_stream_error, Z_OBJ_P(zv), ZEND_STRL("message"), entry->message); - if (options & REPORT_ERRORS) { - /* Report immediately using standard error functions */ - php_stream_wrapper_error_internal_with_name_and_message( - wrapper_name, context, NULL, options, severity, terminal, code, param, message); + zend_update_property_string(php_ce_stream_error, Z_OBJ_P(zv), ZEND_STRL("wrapperName"), + entry->wrapper_name ? entry->wrapper_name : ""); + + zend_update_property_long( + php_ce_stream_error, Z_OBJ_P(zv), ZEND_STRL("severity"), entry->severity); + + zend_update_property_bool( + php_ce_stream_error, Z_OBJ_P(zv), ZEND_STRL("terminating"), entry->terminating); + + if (entry->param) { + zend_update_property_string( + php_ce_stream_error, Z_OBJ_P(zv), ZEND_STRL("param"), entry->param); + } else { + zend_update_property_null(php_ce_stream_error, Z_OBJ_P(zv), ZEND_STRL("param")); + } + + if (entry->next) { + zval next_error; + php_stream_error_create_object(&next_error, entry->next); + zend_update_property(php_ce_stream_error, Z_OBJ_P(zv), ZEND_STRL("next"), &next_error); + zval_ptr_dtor(&next_error); } else { - /* Store for later display in FG(wrapper_logged_errors) */ - php_stream_wrapper_log_store_error(message, code, wrapper_name, param, severity, terminal); + zend_update_property_null(php_ce_stream_error, Z_OBJ_P(zv), ZEND_STRL("next")); } - zend_string_release(message); } -PHPAPI void php_stream_wrapper_log_error(const php_stream_wrapper *wrapper, - php_stream_context *context, int options, int severity, bool terminal, int code, - const char *fmt, ...) + +/* StreamError methods */ + +PHP_METHOD(StreamError, hasCode) { - va_list args; - va_start(args, fmt); - php_stream_wrapper_log_error_internal( - wrapper, context, options, severity, terminal, code, NULL, fmt, args); - va_end(args); + zval *search_code; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_OBJECT_OF_CLASS(search_code, php_ce_stream_error_code) + ZEND_PARSE_PARAMETERS_END(); + + zval *current_error_zv = ZEND_THIS; + + while (Z_TYPE_P(current_error_zv) == IS_OBJECT) { + zval *code_zv = zend_read_property( + php_ce_stream_error, Z_OBJ_P(current_error_zv), + ZEND_STRL("code"), 1, NULL); + + /* Compare enum objects */ + if (Z_TYPE_P(code_zv) == IS_OBJECT && Z_OBJ_P(code_zv) == Z_OBJ_P(search_code)) { + RETURN_TRUE; + } + + /* Move to next error */ + current_error_zv = zend_read_property( + php_ce_stream_error, Z_OBJ_P(current_error_zv), + ZEND_STRL("next"), 1, NULL); + + if (Z_TYPE_P(current_error_zv) != IS_OBJECT) { + break; + } + } + + RETURN_FALSE; } -PHPAPI void php_stream_wrapper_log_error_param(const php_stream_wrapper *wrapper, - php_stream_context *context, int options, int severity, bool terminal, int code, - const char *param, const char *fmt, ...) +PHP_METHOD(StreamError, count) { - va_list args; - va_start(args, fmt); - char *param_copy = param ? estrdup(param) : NULL; - php_stream_wrapper_log_error_internal( - wrapper, context, options, severity, terminal, code, param_copy, fmt, args); - va_end(args); + ZEND_PARSE_PARAMETERS_NONE(); + + zend_long count = 1; + zval *current_error_zv = ZEND_THIS; + + while (1) { + current_error_zv = zend_read_property( + php_ce_stream_error, Z_OBJ_P(current_error_zv), + ZEND_STRL("next"), 1, NULL); + + if (Z_TYPE_P(current_error_zv) != IS_OBJECT) { + break; + } + + count++; + } + + RETURN_LONG(count); } -static zend_llist *php_stream_get_wrapper_errors_list(const char *wrapper_name) +/* StreamException methods */ + +PHP_METHOD(StreamException, getError) { - if (!FG(wrapper_logged_errors)) { - return NULL; - } else { - return (zend_llist *) zend_hash_str_find_ptr( - FG(wrapper_logged_errors), wrapper_name, strlen(wrapper_name)); - } + ZEND_PARSE_PARAMETERS_NONE(); + + zval *error = zend_read_property( + php_ce_stream_exception, Z_OBJ_P(ZEND_THIS), + ZEND_STRL("error"), 1, NULL); + + RETURN_COPY(error); } -PHPAPI void php_stream_display_wrapper_name_errors(const char *wrapper_name, - php_stream_context *context, int code, const char *path, const char *caption) -{ - char *msg; - char errstr[256]; - int free_msg = 0; +/* StreamErrorCode helper */ - if (EG(exception)) { - /* Don't emit additional warnings if an exception has already been thrown. */ - return; +static bool php_stream_error_code_in_range(zval *this_zv, int start, int end) +{ + zval *backing = zend_enum_fetch_case_value(Z_OBJ_P(this_zv)); + if (!backing || Z_TYPE_P(backing) != IS_LONG) { + return false; } - char *tmp = estrdup(path); - if (strcmp(wrapper_name, PHP_STREAM_ERROR_WRAPPER_DEFAULT_NAME)) { - zend_llist *err_list = php_stream_get_wrapper_errors_list(wrapper_name); - if (err_list) { - size_t l = 0; - int brlen; - int i; - int count = (int) zend_llist_count(err_list); - const char *br; - php_stream_error_entry **err_entry_p; - zend_llist_position pos; - - if (PG(html_errors)) { - brlen = 7; - br = "
\n"; - } else { - brlen = 1; - br = "\n"; - } - - for (err_entry_p = zend_llist_get_first_ex(err_list, &pos), i = 0; err_entry_p; - err_entry_p = zend_llist_get_next_ex(err_list, &pos), i++) { - l += ZSTR_LEN((*err_entry_p)->message); - if (i < count - 1) { - l += brlen; - } - } - msg = emalloc(l + 1); - msg[0] = '\0'; - for (err_entry_p = zend_llist_get_first_ex(err_list, &pos), i = 0; err_entry_p; - err_entry_p = zend_llist_get_next_ex(err_list, &pos), i++) { - strcat(msg, ZSTR_VAL((*err_entry_p)->message)); - if (i < count - 1) { - strcat(msg, br); - } - } + zend_long value = Z_LVAL_P(backing); + return value >= start && value < end; +} - free_msg = 1; - } else { - if (!strcmp(wrapper_name, php_plain_files_wrapper.wops->label)) { - msg = php_socket_strerror_s(errno, errstr, sizeof(errstr)); - } else { - msg = "operation failed"; - } - } - } else { - msg = "no suitable wrapper could be found"; - } +/* StreamErrorCode methods */ - php_strip_url_passwd(tmp); - php_stream_wrapper_error_internal_with_name_variadic(wrapper_name, context, NULL, REPORT_ERRORS, - E_WARNING, true, code, tmp, "%s: %s", caption, msg); +PHP_METHOD(StreamErrorCode, isIoError) +{ + ZEND_PARSE_PARAMETERS_NONE(); - if (free_msg) { - efree(msg); - } + RETURN_BOOL(php_stream_error_code_in_range( + ZEND_THIS, STREAM_ERROR_CODE_IO_START, STREAM_ERROR_CODE_IO_END)); } -PHPAPI void php_stream_display_wrapper_errors(php_stream_wrapper *wrapper, - php_stream_context *context, int code, const char *path, const char *caption) +PHP_METHOD(StreamErrorCode, isFileSystemError) { - if (wrapper) { - const char *wrapper_name = PHP_STREAM_ERROR_WRAPPER_NAME(wrapper); - php_stream_display_wrapper_name_errors(wrapper_name, context, code, path, caption); - } + ZEND_PARSE_PARAMETERS_NONE(); + + RETURN_BOOL(php_stream_error_code_in_range( + ZEND_THIS, STREAM_ERROR_CODE_FILESYSTEM_START, STREAM_ERROR_CODE_FILESYSTEM_END)); } -PHPAPI void php_stream_tidy_wrapper_name_error_log(const char *wrapper_name) +PHP_METHOD(StreamErrorCode, isWrapperError) { - if (FG(wrapper_logged_errors)) { - zend_hash_str_del(FG(wrapper_logged_errors), wrapper_name, strlen(wrapper_name)); - } + ZEND_PARSE_PARAMETERS_NONE(); + + RETURN_BOOL(php_stream_error_code_in_range( + ZEND_THIS, STREAM_ERROR_CODE_WRAPPER_START, STREAM_ERROR_CODE_WRAPPER_END)); } -PHPAPI void php_stream_tidy_wrapper_error_log(php_stream_wrapper *wrapper) +PHP_METHOD(StreamErrorCode, isFilterError) { - if (wrapper) { - const char *wrapper_name = PHP_STREAM_ERROR_WRAPPER_NAME(wrapper); - php_stream_tidy_wrapper_name_error_log(wrapper_name); - } -} + ZEND_PARSE_PARAMETERS_NONE(); -/* Stream error reporting */ + RETURN_BOOL(php_stream_error_code_in_range( + ZEND_THIS, STREAM_ERROR_CODE_FILTER_START, STREAM_ERROR_CODE_FILTER_END)); +} -PHPAPI void php_stream_error(php_stream *stream, const char *docref, int severity, bool terminal, - int code, const char *fmt, ...) +PHP_METHOD(StreamErrorCode, isCastError) { - va_list args; - va_start(args, fmt); - zend_string *message = vstrpprintf(0, fmt, args); - va_end(args); + ZEND_PARSE_PARAMETERS_NONE(); - php_stream_wrapper *wrapper = stream->wrapper; - const char *wrapper_name = wrapper ? wrapper->wops->label : "stream"; + RETURN_BOOL(php_stream_error_code_in_range( + ZEND_THIS, STREAM_ERROR_CODE_CAST_START, STREAM_ERROR_CODE_CAST_END)); +} - php_stream_context *context = PHP_STREAM_CONTEXT(stream); +PHP_METHOD(StreamErrorCode, isNetworkError) +{ + ZEND_PARSE_PARAMETERS_NONE(); - /* Process the error - always report for stream errors */ - php_stream_process_error(context, wrapper_name, stream, docref, code, ZSTR_VAL(message), NULL, - severity, terminal); + RETURN_BOOL(php_stream_error_code_in_range( + ZEND_THIS, STREAM_ERROR_CODE_NETWORK_START, STREAM_ERROR_CODE_NETWORK_END)); +} - /* Store error */ - php_stream_store_error_common( - context, stream, message, docref, code, wrapper_name, NULL, severity, terminal); +PHP_METHOD(StreamErrorCode, isEncodingError) +{ + ZEND_PARSE_PARAMETERS_NONE(); - zend_string_release(message); + RETURN_BOOL(php_stream_error_code_in_range( + ZEND_THIS, STREAM_ERROR_CODE_ENCODING_START, STREAM_ERROR_CODE_ENCODING_END)); } -/* StreamException class and error constants registration */ - -PHP_MINIT_FUNCTION(stream_errors) +PHP_METHOD(StreamErrorCode, isResourceError) { - register_stream_errors_symbols(module_number); - - php_ce_stream_exception = register_class_StreamException(zend_ce_exception); + ZEND_PARSE_PARAMETERS_NONE(); - return SUCCESS; + RETURN_BOOL(php_stream_error_code_in_range( + ZEND_THIS, STREAM_ERROR_CODE_RESOURCE_START, STREAM_ERROR_CODE_RESOURCE_END)); } -PHP_METHOD(StreamException, getParam) +PHP_METHOD(StreamErrorCode, isLockError) { ZEND_PARSE_PARAMETERS_NONE(); - zval *param = zend_read_property( - php_ce_stream_exception, Z_OBJ_P(getThis()), ZEND_STRL("param"), 1, NULL); - RETURN_COPY(param); + RETURN_BOOL(php_stream_error_code_in_range( + ZEND_THIS, STREAM_ERROR_CODE_LOCK_START, STREAM_ERROR_CODE_LOCK_END)); } -PHP_METHOD(StreamException, getWrapperName) +PHP_METHOD(StreamErrorCode, isUserspaceError) { ZEND_PARSE_PARAMETERS_NONE(); - zval *wrapper_name = zend_read_property( - php_ce_stream_exception, Z_OBJ_P(getThis()), ZEND_STRL("wrapperName"), 1, NULL); - RETURN_COPY(wrapper_name); + RETURN_BOOL(php_stream_error_code_in_range( + ZEND_THIS, STREAM_ERROR_CODE_USERSPACE_START, STREAM_ERROR_CODE_USERSPACE_END)); +} + +/* Module init */ + +PHP_MINIT_FUNCTION(stream_errors) +{ + /* Register enums */ + php_ce_stream_error_code = register_class_StreamErrorCode(); + php_ce_stream_error_mode = register_class_StreamErrorMode(); + php_ce_stream_error_store = register_class_StreamErrorStore(); + + /* Add cases to StreamErrorCode */ +#define V(uc_name, name, val) \ + { \ + zval enum_case_value; \ + ZVAL_LONG(&enum_case_value, val); \ + zend_enum_add_case_cstr(php_ce_stream_error_code, #name, &enum_case_value); \ + } + PHP_STREAM_ERROR_CODES(V) +#undef V + + /* Register classes */ + php_ce_stream_error = register_class_StreamError(); + php_ce_stream_exception = register_class_StreamException(zend_ce_exception); + + return SUCCESS; +} + +PHP_MSHUTDOWN_FUNCTION(stream_errors) +{ + return SUCCESS; } diff --git a/main/streams/stream_errors.stub.php b/main/streams/stream_errors.stub.php index 61779037fdc6c..83e44ca75c9bf 100644 --- a/main/streams/stream_errors.stub.php +++ b/main/streams/stream_errors.stub.php @@ -2,434 +2,65 @@ /** @generate-class-entries static */ -class StreamException extends Exception +enum StreamErrorCode: int { - protected ?string $wrapperName = null; - protected ?string $param = null; + // Error code cases registered in code + + public function isIoError(): bool {} + + public function isFileSystemError(): bool {} + + public function isWrapperError(): bool {} + + public function isFilterError(): bool {} + + public function isCastError(): bool {} + + public function isNetworkError(): bool {} + + public function isEncodingError(): bool {} + + public function isResourceError(): bool {} + + public function isLockError(): bool {} + + public function isUserspaceError(): bool {} +} - public function getParam(): ?string {} - public function getWrapperName(): ?string {} +enum StreamErrorMode +{ + case Error; + case Exception; + case Silent; +} + +enum StreamErrorStore +{ + case Auto; + case None; + case NonTerminal; + case Terminal; + case All; } -/** - * @var int - * @cvalue PHP_STREAM_ERROR_MODE_ERROR - */ -const STREAM_ERROR_MODE_ERROR = UNKNOWN; -/** - * @var int - * @cvalue PHP_STREAM_ERROR_MODE_EXCEPTION - */ -const STREAM_ERROR_MODE_EXCEPTION = UNKNOWN; -/** - * @var int - * @cvalue PHP_STREAM_ERROR_MODE_SILENT - */ -const STREAM_ERROR_MODE_SILENT = UNKNOWN; +final readonly class StreamError +{ + public StreamErrorCode $code; + public string $message; + public string $wrapperName; + public int $severity; + public bool $terminating; + public ?string $param; + public ?StreamError $next; + + public function hasCode(StreamErrorCode $code): bool {} -/** - * @var int - * @cvalue PHP_STREAM_ERROR_STORE_AUTO - */ -const STREAM_ERROR_STORE_AUTO = UNKNOWN; -/** - * @var int - * @cvalue PHP_STREAM_ERROR_STORE_NONE - */ -const STREAM_ERROR_STORE_NONE = UNKNOWN; -/** - * @var int - * @cvalue PHP_STREAM_ERROR_STORE_NON_TERM - */ -const STREAM_ERROR_STORE_NON_TERMINAL = UNKNOWN; -/** - * @var int - * @cvalue PHP_STREAM_ERROR_STORE_TERMINAL - */ -const STREAM_ERROR_STORE_TERMINAL = UNKNOWN; -/** - * @var int - * @cvalue PHP_STREAM_ERROR_STORE_ALL - */ -const STREAM_ERROR_STORE_ALL = UNKNOWN; + public function count(): int {} +} -/** - * @var int - * @cvalue STREAM_ERROR_CODE_NONE - */ -const STREAM_ERROR_CODE_NONE = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_GENERIC - */ -const STREAM_ERROR_CODE_GENERIC = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_READ_FAILED - */ -const STREAM_ERROR_CODE_READ_FAILED = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_WRITE_FAILED - */ -const STREAM_ERROR_CODE_WRITE_FAILED = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_SEEK_FAILED - */ -const STREAM_ERROR_CODE_SEEK_FAILED = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_SEEK_NOT_SUPPORTED - */ -const STREAM_ERROR_CODE_SEEK_NOT_SUPPORTED = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_FLUSH_FAILED - */ -const STREAM_ERROR_CODE_FLUSH_FAILED = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_TRUNCATE_FAILED - */ -const STREAM_ERROR_CODE_TRUNCATE_FAILED = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_CONNECT_FAILED - */ -const STREAM_ERROR_CODE_CONNECT_FAILED = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_BIND_FAILED - */ -const STREAM_ERROR_CODE_BIND_FAILED = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_LISTEN_FAILED - */ -const STREAM_ERROR_CODE_LISTEN_FAILED = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_NOT_WRITABLE - */ -const STREAM_ERROR_CODE_NOT_WRITABLE = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_NOT_READABLE - */ -const STREAM_ERROR_CODE_NOT_READABLE = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_DISABLED - */ -const STREAM_ERROR_CODE_DISABLED = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_NOT_FOUND - */ -const STREAM_ERROR_CODE_NOT_FOUND = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_PERMISSION_DENIED - */ -const STREAM_ERROR_CODE_PERMISSION_DENIED = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_ALREADY_EXISTS - */ -const STREAM_ERROR_CODE_ALREADY_EXISTS = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_INVALID_PATH - */ -const STREAM_ERROR_CODE_INVALID_PATH = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_PATH_TOO_LONG - */ -const STREAM_ERROR_CODE_PATH_TOO_LONG = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_CREATE_FAILED - */ -const STREAM_ERROR_CODE_CREATE_FAILED = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_DUP_FAILED - */ -const STREAM_ERROR_CODE_DUP_FAILED = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_OPEN_FAILED - */ -const STREAM_ERROR_CODE_OPEN_FAILED = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_UNLINK_FAILED - */ -const STREAM_ERROR_CODE_UNLINK_FAILED = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_RENAME_FAILED - */ -const STREAM_ERROR_CODE_RENAME_FAILED = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_MKDIR_FAILED - */ -const STREAM_ERROR_CODE_MKDIR_FAILED = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_RMDIR_FAILED - */ -const STREAM_ERROR_CODE_RMDIR_FAILED = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_STAT_FAILED - */ -const STREAM_ERROR_CODE_STAT_FAILED = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_META_FAILED - */ -const STREAM_ERROR_CODE_META_FAILED = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_CHMOD_FAILED - */ -const STREAM_ERROR_CODE_CHMOD_FAILED = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_CHOWN_FAILED - */ -const STREAM_ERROR_CODE_CHOWN_FAILED = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_COPY_FAILED - */ -const STREAM_ERROR_CODE_COPY_FAILED = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_TOUCH_FAILED - */ -const STREAM_ERROR_CODE_TOUCH_FAILED = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_INVALID_MODE - */ -const STREAM_ERROR_CODE_INVALID_MODE = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_INVALID_META - */ -const STREAM_ERROR_CODE_INVALID_META = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_MODE_NOT_SUPPORTED - */ -const STREAM_ERROR_CODE_MODE_NOT_SUPPORTED = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_READONLY - */ -const STREAM_ERROR_CODE_READONLY = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_RECURSION_DETECTED - */ -const STREAM_ERROR_CODE_RECURSION_DETECTED = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_NOT_IMPLEMENTED - */ -const STREAM_ERROR_CODE_NOT_IMPLEMENTED = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_NO_OPENER - */ -const STREAM_ERROR_CODE_NO_OPENER = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_PERSISTENT_NOT_SUPPORTED - */ -const STREAM_ERROR_CODE_PERSISTENT_NOT_SUPPORTED = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_WRAPPER_NOT_FOUND - */ -const STREAM_ERROR_CODE_WRAPPER_NOT_FOUND = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_WRAPPER_DISABLED - */ -const STREAM_ERROR_CODE_WRAPPER_DISABLED = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_PROTOCOL_UNSUPPORTED - */ -const STREAM_ERROR_CODE_PROTOCOL_UNSUPPORTED = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_WRAPPER_REGISTRATION_FAILED - */ -const STREAM_ERROR_CODE_WRAPPER_REGISTRATION_FAILED = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_WRAPPER_UNREGISTRATION_FAILED - */ -const STREAM_ERROR_CODE_WRAPPER_UNREGISTRATION_FAILED = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_WRAPPER_RESTORATION_FAILED - */ -const STREAM_ERROR_CODE_WRAPPER_RESTORATION_FAILED = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_FILTER_NOT_FOUND - */ -const STREAM_ERROR_CODE_FILTER_NOT_FOUND = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_FILTER_FAILED - */ -const STREAM_ERROR_CODE_FILTER_FAILED = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_CAST_FAILED - */ -const STREAM_ERROR_CODE_CAST_FAILED = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_CAST_NOT_SUPPORTED - */ -const STREAM_ERROR_CODE_CAST_NOT_SUPPORTED = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_MAKE_SEEKABLE_FAILED - */ -const STREAM_ERROR_CODE_MAKE_SEEKABLE_FAILED = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_BUFFERED_DATA_LOST - */ -const STREAM_ERROR_CODE_BUFFERED_DATA_LOST = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_NETWORK_SEND_FAILED - */ -const STREAM_ERROR_CODE_NETWORK_SEND_FAILED = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_NETWORK_RECV_FAILED - */ -const STREAM_ERROR_CODE_NETWORK_RECV_FAILED = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_SSL_NOT_SUPPORTED - */ -const STREAM_ERROR_CODE_SSL_NOT_SUPPORTED = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_RESUMPTION_FAILED - */ -const STREAM_ERROR_CODE_RESUMPTION_FAILED = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_SOCKET_PATH_TOO_LONG - */ -const STREAM_ERROR_CODE_SOCKET_PATH_TOO_LONG = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_OOB_NOT_SUPPORTED - */ -const STREAM_ERROR_CODE_OOB_NOT_SUPPORTED = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_PROTOCOL_ERROR - */ -const STREAM_ERROR_CODE_PROTOCOL_ERROR = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_INVALID_URL - */ -const STREAM_ERROR_CODE_INVALID_URL = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_INVALID_RESPONSE - */ -const STREAM_ERROR_CODE_INVALID_RESPONSE = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_INVALID_HEADER - */ -const STREAM_ERROR_CODE_INVALID_HEADER = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_INVALID_PARAM - */ -const STREAM_ERROR_CODE_INVALID_PARAM = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_REDIRECT_LIMIT - */ -const STREAM_ERROR_CODE_REDIRECT_LIMIT = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_AUTH_FAILED - */ -const STREAM_ERROR_CODE_AUTH_FAILED = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_ARCHIVING_FAILED - */ -const STREAM_ERROR_CODE_ARCHIVING_FAILED = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_ENCODING_FAILED - */ -const STREAM_ERROR_CODE_ENCODING_FAILED = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_DECODING_FAILED - */ -const STREAM_ERROR_CODE_DECODING_FAILED = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_INVALID_FORMAT - */ -const STREAM_ERROR_CODE_INVALID_FORMAT = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_ALLOCATION_FAILED - */ -const STREAM_ERROR_CODE_ALLOCATION_FAILED = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_TEMPORARY_FILE_FAILED - */ -const STREAM_ERROR_CODE_TEMPORARY_FILE_FAILED = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_LOCK_FAILED - */ -const STREAM_ERROR_CODE_LOCK_FAILED = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_LOCK_NOT_SUPPORTED - */ -const STREAM_ERROR_CODE_LOCK_NOT_SUPPORTED = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_USERSPACE_NOT_IMPLEMENTED - */ -const STREAM_ERROR_CODE_USERSPACE_NOT_IMPLEMENTED = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_USERSPACE_INVALID_RETURN - */ -const STREAM_ERROR_CODE_USERSPACE_INVALID_RETURN = UNKNOWN; -/** - * @var int - * @cvalue STREAM_ERROR_CODE_USERSPACE_CALL_FAILED - */ -const STREAM_ERROR_CODE_USERSPACE_CALL_FAILED = UNKNOWN; +class StreamException extends Exception +{ + private ?StreamError $error = null; + + public function getError(): ?StreamError {} +} diff --git a/main/streams/stream_errors_arginfo.h b/main/streams/stream_errors_arginfo.h index 5c21a632755a9..1675213fd99ae 100644 --- a/main/streams/stream_errors_arginfo.h +++ b/main/streams/stream_errors_arginfo.h @@ -1,126 +1,174 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: afc1e2ff4a74033102ca8b69ea55ab9ce30986da */ + * Stub hash: c9a7e6c0b34de0c6ee76c2a9d80c50deafc8079a */ -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_StreamException_getParam, 0, 0, IS_STRING, 1) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_StreamErrorCode_isIoError, 0, 0, _IS_BOOL, 0) ZEND_END_ARG_INFO() -#define arginfo_class_StreamException_getWrapperName arginfo_class_StreamException_getParam +#define arginfo_class_StreamErrorCode_isFileSystemError arginfo_class_StreamErrorCode_isIoError -static ZEND_METHOD(StreamException, getParam); -static ZEND_METHOD(StreamException, getWrapperName); +#define arginfo_class_StreamErrorCode_isWrapperError arginfo_class_StreamErrorCode_isIoError + +#define arginfo_class_StreamErrorCode_isFilterError arginfo_class_StreamErrorCode_isIoError + +#define arginfo_class_StreamErrorCode_isCastError arginfo_class_StreamErrorCode_isIoError + +#define arginfo_class_StreamErrorCode_isNetworkError arginfo_class_StreamErrorCode_isIoError + +#define arginfo_class_StreamErrorCode_isEncodingError arginfo_class_StreamErrorCode_isIoError + +#define arginfo_class_StreamErrorCode_isResourceError arginfo_class_StreamErrorCode_isIoError + +#define arginfo_class_StreamErrorCode_isLockError arginfo_class_StreamErrorCode_isIoError + +#define arginfo_class_StreamErrorCode_isUserspaceError arginfo_class_StreamErrorCode_isIoError + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_StreamError_hasCode, 0, 1, _IS_BOOL, 0) + ZEND_ARG_OBJ_INFO(0, code, StreamErrorCode, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_StreamError_count, 0, 0, IS_LONG, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_StreamException_getError, 0, 0, StreamError, 1) +ZEND_END_ARG_INFO() + +static ZEND_METHOD(StreamErrorCode, isIoError); +static ZEND_METHOD(StreamErrorCode, isFileSystemError); +static ZEND_METHOD(StreamErrorCode, isWrapperError); +static ZEND_METHOD(StreamErrorCode, isFilterError); +static ZEND_METHOD(StreamErrorCode, isCastError); +static ZEND_METHOD(StreamErrorCode, isNetworkError); +static ZEND_METHOD(StreamErrorCode, isEncodingError); +static ZEND_METHOD(StreamErrorCode, isResourceError); +static ZEND_METHOD(StreamErrorCode, isLockError); +static ZEND_METHOD(StreamErrorCode, isUserspaceError); +static ZEND_METHOD(StreamError, hasCode); +static ZEND_METHOD(StreamError, count); +static ZEND_METHOD(StreamException, getError); + +static const zend_function_entry class_StreamErrorCode_methods[] = { + ZEND_ME(StreamErrorCode, isIoError, arginfo_class_StreamErrorCode_isIoError, ZEND_ACC_PUBLIC) + ZEND_ME(StreamErrorCode, isFileSystemError, arginfo_class_StreamErrorCode_isFileSystemError, ZEND_ACC_PUBLIC) + ZEND_ME(StreamErrorCode, isWrapperError, arginfo_class_StreamErrorCode_isWrapperError, ZEND_ACC_PUBLIC) + ZEND_ME(StreamErrorCode, isFilterError, arginfo_class_StreamErrorCode_isFilterError, ZEND_ACC_PUBLIC) + ZEND_ME(StreamErrorCode, isCastError, arginfo_class_StreamErrorCode_isCastError, ZEND_ACC_PUBLIC) + ZEND_ME(StreamErrorCode, isNetworkError, arginfo_class_StreamErrorCode_isNetworkError, ZEND_ACC_PUBLIC) + ZEND_ME(StreamErrorCode, isEncodingError, arginfo_class_StreamErrorCode_isEncodingError, ZEND_ACC_PUBLIC) + ZEND_ME(StreamErrorCode, isResourceError, arginfo_class_StreamErrorCode_isResourceError, ZEND_ACC_PUBLIC) + ZEND_ME(StreamErrorCode, isLockError, arginfo_class_StreamErrorCode_isLockError, ZEND_ACC_PUBLIC) + ZEND_ME(StreamErrorCode, isUserspaceError, arginfo_class_StreamErrorCode_isUserspaceError, ZEND_ACC_PUBLIC) + ZEND_FE_END +}; + +static const zend_function_entry class_StreamError_methods[] = { + ZEND_ME(StreamError, hasCode, arginfo_class_StreamError_hasCode, ZEND_ACC_PUBLIC) + ZEND_ME(StreamError, count, arginfo_class_StreamError_count, ZEND_ACC_PUBLIC) + ZEND_FE_END +}; static const zend_function_entry class_StreamException_methods[] = { - ZEND_ME(StreamException, getParam, arginfo_class_StreamException_getParam, ZEND_ACC_PUBLIC) - ZEND_ME(StreamException, getWrapperName, arginfo_class_StreamException_getWrapperName, ZEND_ACC_PUBLIC) + ZEND_ME(StreamException, getError, arginfo_class_StreamException_getError, ZEND_ACC_PUBLIC) ZEND_FE_END }; -static void register_stream_errors_symbols(int module_number) +static zend_class_entry *register_class_StreamErrorCode(void) { - REGISTER_LONG_CONSTANT("STREAM_ERROR_MODE_ERROR", PHP_STREAM_ERROR_MODE_ERROR, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_MODE_EXCEPTION", PHP_STREAM_ERROR_MODE_EXCEPTION, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_MODE_SILENT", PHP_STREAM_ERROR_MODE_SILENT, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_STORE_AUTO", PHP_STREAM_ERROR_STORE_AUTO, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_STORE_NONE", PHP_STREAM_ERROR_STORE_NONE, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_STORE_NON_TERMINAL", PHP_STREAM_ERROR_STORE_NON_TERM, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_STORE_TERMINAL", PHP_STREAM_ERROR_STORE_TERMINAL, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_STORE_ALL", PHP_STREAM_ERROR_STORE_ALL, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_NONE", STREAM_ERROR_CODE_NONE, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_GENERIC", STREAM_ERROR_CODE_GENERIC, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_READ_FAILED", STREAM_ERROR_CODE_READ_FAILED, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_WRITE_FAILED", STREAM_ERROR_CODE_WRITE_FAILED, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_SEEK_FAILED", STREAM_ERROR_CODE_SEEK_FAILED, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_SEEK_NOT_SUPPORTED", STREAM_ERROR_CODE_SEEK_NOT_SUPPORTED, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_FLUSH_FAILED", STREAM_ERROR_CODE_FLUSH_FAILED, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_TRUNCATE_FAILED", STREAM_ERROR_CODE_TRUNCATE_FAILED, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_CONNECT_FAILED", STREAM_ERROR_CODE_CONNECT_FAILED, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_BIND_FAILED", STREAM_ERROR_CODE_BIND_FAILED, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_LISTEN_FAILED", STREAM_ERROR_CODE_LISTEN_FAILED, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_NOT_WRITABLE", STREAM_ERROR_CODE_NOT_WRITABLE, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_NOT_READABLE", STREAM_ERROR_CODE_NOT_READABLE, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_DISABLED", STREAM_ERROR_CODE_DISABLED, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_NOT_FOUND", STREAM_ERROR_CODE_NOT_FOUND, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_PERMISSION_DENIED", STREAM_ERROR_CODE_PERMISSION_DENIED, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_ALREADY_EXISTS", STREAM_ERROR_CODE_ALREADY_EXISTS, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_INVALID_PATH", STREAM_ERROR_CODE_INVALID_PATH, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_PATH_TOO_LONG", STREAM_ERROR_CODE_PATH_TOO_LONG, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_CREATE_FAILED", STREAM_ERROR_CODE_CREATE_FAILED, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_DUP_FAILED", STREAM_ERROR_CODE_DUP_FAILED, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_OPEN_FAILED", STREAM_ERROR_CODE_OPEN_FAILED, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_UNLINK_FAILED", STREAM_ERROR_CODE_UNLINK_FAILED, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_RENAME_FAILED", STREAM_ERROR_CODE_RENAME_FAILED, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_MKDIR_FAILED", STREAM_ERROR_CODE_MKDIR_FAILED, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_RMDIR_FAILED", STREAM_ERROR_CODE_RMDIR_FAILED, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_STAT_FAILED", STREAM_ERROR_CODE_STAT_FAILED, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_META_FAILED", STREAM_ERROR_CODE_META_FAILED, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_CHMOD_FAILED", STREAM_ERROR_CODE_CHMOD_FAILED, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_CHOWN_FAILED", STREAM_ERROR_CODE_CHOWN_FAILED, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_COPY_FAILED", STREAM_ERROR_CODE_COPY_FAILED, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_TOUCH_FAILED", STREAM_ERROR_CODE_TOUCH_FAILED, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_INVALID_MODE", STREAM_ERROR_CODE_INVALID_MODE, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_INVALID_META", STREAM_ERROR_CODE_INVALID_META, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_MODE_NOT_SUPPORTED", STREAM_ERROR_CODE_MODE_NOT_SUPPORTED, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_READONLY", STREAM_ERROR_CODE_READONLY, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_RECURSION_DETECTED", STREAM_ERROR_CODE_RECURSION_DETECTED, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_NOT_IMPLEMENTED", STREAM_ERROR_CODE_NOT_IMPLEMENTED, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_NO_OPENER", STREAM_ERROR_CODE_NO_OPENER, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_PERSISTENT_NOT_SUPPORTED", STREAM_ERROR_CODE_PERSISTENT_NOT_SUPPORTED, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_WRAPPER_NOT_FOUND", STREAM_ERROR_CODE_WRAPPER_NOT_FOUND, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_WRAPPER_DISABLED", STREAM_ERROR_CODE_WRAPPER_DISABLED, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_PROTOCOL_UNSUPPORTED", STREAM_ERROR_CODE_PROTOCOL_UNSUPPORTED, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_WRAPPER_REGISTRATION_FAILED", STREAM_ERROR_CODE_WRAPPER_REGISTRATION_FAILED, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_WRAPPER_UNREGISTRATION_FAILED", STREAM_ERROR_CODE_WRAPPER_UNREGISTRATION_FAILED, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_WRAPPER_RESTORATION_FAILED", STREAM_ERROR_CODE_WRAPPER_RESTORATION_FAILED, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_FILTER_NOT_FOUND", STREAM_ERROR_CODE_FILTER_NOT_FOUND, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_FILTER_FAILED", STREAM_ERROR_CODE_FILTER_FAILED, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_CAST_FAILED", STREAM_ERROR_CODE_CAST_FAILED, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_CAST_NOT_SUPPORTED", STREAM_ERROR_CODE_CAST_NOT_SUPPORTED, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_MAKE_SEEKABLE_FAILED", STREAM_ERROR_CODE_MAKE_SEEKABLE_FAILED, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_BUFFERED_DATA_LOST", STREAM_ERROR_CODE_BUFFERED_DATA_LOST, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_NETWORK_SEND_FAILED", STREAM_ERROR_CODE_NETWORK_SEND_FAILED, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_NETWORK_RECV_FAILED", STREAM_ERROR_CODE_NETWORK_RECV_FAILED, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_SSL_NOT_SUPPORTED", STREAM_ERROR_CODE_SSL_NOT_SUPPORTED, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_RESUMPTION_FAILED", STREAM_ERROR_CODE_RESUMPTION_FAILED, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_SOCKET_PATH_TOO_LONG", STREAM_ERROR_CODE_SOCKET_PATH_TOO_LONG, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_OOB_NOT_SUPPORTED", STREAM_ERROR_CODE_OOB_NOT_SUPPORTED, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_PROTOCOL_ERROR", STREAM_ERROR_CODE_PROTOCOL_ERROR, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_INVALID_URL", STREAM_ERROR_CODE_INVALID_URL, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_INVALID_RESPONSE", STREAM_ERROR_CODE_INVALID_RESPONSE, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_INVALID_HEADER", STREAM_ERROR_CODE_INVALID_HEADER, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_INVALID_PARAM", STREAM_ERROR_CODE_INVALID_PARAM, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_REDIRECT_LIMIT", STREAM_ERROR_CODE_REDIRECT_LIMIT, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_AUTH_FAILED", STREAM_ERROR_CODE_AUTH_FAILED, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_ARCHIVING_FAILED", STREAM_ERROR_CODE_ARCHIVING_FAILED, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_ENCODING_FAILED", STREAM_ERROR_CODE_ENCODING_FAILED, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_DECODING_FAILED", STREAM_ERROR_CODE_DECODING_FAILED, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_INVALID_FORMAT", STREAM_ERROR_CODE_INVALID_FORMAT, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_ALLOCATION_FAILED", STREAM_ERROR_CODE_ALLOCATION_FAILED, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_TEMPORARY_FILE_FAILED", STREAM_ERROR_CODE_TEMPORARY_FILE_FAILED, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_LOCK_FAILED", STREAM_ERROR_CODE_LOCK_FAILED, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_LOCK_NOT_SUPPORTED", STREAM_ERROR_CODE_LOCK_NOT_SUPPORTED, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_USERSPACE_NOT_IMPLEMENTED", STREAM_ERROR_CODE_USERSPACE_NOT_IMPLEMENTED, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_USERSPACE_INVALID_RETURN", STREAM_ERROR_CODE_USERSPACE_INVALID_RETURN, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_ERROR_CODE_USERSPACE_CALL_FAILED", STREAM_ERROR_CODE_USERSPACE_CALL_FAILED, CONST_PERSISTENT); + zend_class_entry *class_entry = zend_register_internal_enum("StreamErrorCode", IS_LONG, class_StreamErrorCode_methods); + + return class_entry; } -static zend_class_entry *register_class_StreamException(zend_class_entry *class_entry_Exception) +static zend_class_entry *register_class_StreamErrorMode(void) +{ + zend_class_entry *class_entry = zend_register_internal_enum("StreamErrorMode", IS_UNDEF, NULL); + + zend_enum_add_case_cstr(class_entry, "Error", NULL); + + zend_enum_add_case_cstr(class_entry, "Exception", NULL); + + zend_enum_add_case_cstr(class_entry, "Silent", NULL); + + return class_entry; +} + +static zend_class_entry *register_class_StreamErrorStore(void) +{ + zend_class_entry *class_entry = zend_register_internal_enum("StreamErrorStore", IS_UNDEF, NULL); + + zend_enum_add_case_cstr(class_entry, "Auto", NULL); + + zend_enum_add_case_cstr(class_entry, "None", NULL); + + zend_enum_add_case_cstr(class_entry, "NonTerminal", NULL); + + zend_enum_add_case_cstr(class_entry, "Terminal", NULL); + + zend_enum_add_case_cstr(class_entry, "All", NULL); + + return class_entry; +} + +static zend_class_entry *register_class_StreamError(void) { zend_class_entry ce, *class_entry; - INIT_CLASS_ENTRY(ce, "StreamException", class_StreamException_methods); - class_entry = zend_register_internal_class_with_flags(&ce, class_entry_Exception, 0); + INIT_CLASS_ENTRY(ce, "StreamError", class_StreamError_methods); + class_entry = zend_register_internal_class_with_flags(&ce, NULL, ZEND_ACC_FINAL|ZEND_ACC_READONLY_CLASS); + + zval property_code_default_value; + ZVAL_UNDEF(&property_code_default_value); + zend_string *property_code_class_StreamErrorCode = zend_string_init("StreamErrorCode", sizeof("StreamErrorCode")-1, 1); + zend_declare_typed_property(class_entry, ZSTR_KNOWN(ZEND_STR_CODE), &property_code_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_CLASS(property_code_class_StreamErrorCode, 0, 0)); + + zval property_message_default_value; + ZVAL_UNDEF(&property_message_default_value); + zend_declare_typed_property(class_entry, ZSTR_KNOWN(ZEND_STR_MESSAGE), &property_message_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING)); zval property_wrapperName_default_value; - ZVAL_NULL(&property_wrapperName_default_value); + ZVAL_UNDEF(&property_wrapperName_default_value); zend_string *property_wrapperName_name = zend_string_init("wrapperName", sizeof("wrapperName") - 1, true); - zend_declare_typed_property(class_entry, property_wrapperName_name, &property_wrapperName_default_value, ZEND_ACC_PROTECTED, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING|MAY_BE_NULL)); + zend_declare_typed_property(class_entry, property_wrapperName_name, &property_wrapperName_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING)); zend_string_release_ex(property_wrapperName_name, true); + zval property_severity_default_value; + ZVAL_UNDEF(&property_severity_default_value); + zend_declare_typed_property(class_entry, ZSTR_KNOWN(ZEND_STR_SEVERITY), &property_severity_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + + zval property_terminating_default_value; + ZVAL_UNDEF(&property_terminating_default_value); + zend_string *property_terminating_name = zend_string_init("terminating", sizeof("terminating") - 1, true); + zend_declare_typed_property(class_entry, property_terminating_name, &property_terminating_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_BOOL)); + zend_string_release_ex(property_terminating_name, true); + zval property_param_default_value; - ZVAL_NULL(&property_param_default_value); + ZVAL_UNDEF(&property_param_default_value); zend_string *property_param_name = zend_string_init("param", sizeof("param") - 1, true); - zend_declare_typed_property(class_entry, property_param_name, &property_param_default_value, ZEND_ACC_PROTECTED, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING|MAY_BE_NULL)); + zend_declare_typed_property(class_entry, property_param_name, &property_param_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING|MAY_BE_NULL)); zend_string_release_ex(property_param_name, true); + zval property_next_default_value; + ZVAL_UNDEF(&property_next_default_value); + zend_string *property_next_name = zend_string_init("next", sizeof("next") - 1, true); + zend_string *property_next_class_StreamError = zend_string_init("StreamError", sizeof("StreamError")-1, 1); + zend_declare_typed_property(class_entry, property_next_name, &property_next_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_CLASS(property_next_class_StreamError, 0, MAY_BE_NULL)); + zend_string_release_ex(property_next_name, true); + + return class_entry; +} + +static zend_class_entry *register_class_StreamException(zend_class_entry *class_entry_Exception) +{ + zend_class_entry ce, *class_entry; + + INIT_CLASS_ENTRY(ce, "StreamException", class_StreamException_methods); + class_entry = zend_register_internal_class_with_flags(&ce, class_entry_Exception, 0); + + zval property_error_default_value; + ZVAL_NULL(&property_error_default_value); + zend_string *property_error_name = zend_string_init("error", sizeof("error") - 1, true); + zend_string *property_error_class_StreamError = zend_string_init("StreamError", sizeof("StreamError")-1, 1); + zend_declare_typed_property(class_entry, property_error_name, &property_error_default_value, ZEND_ACC_PRIVATE, NULL, (zend_type) ZEND_TYPE_INIT_CLASS(property_error_class_StreamError, 0, MAY_BE_NULL)); + zend_string_release_ex(property_error_name, true); + return class_entry; } diff --git a/main/streams/streams.c b/main/streams/streams.c index 328104aae9745..eaebd1564b4dd 100644 --- a/main/streams/streams.c +++ b/main/streams/streams.c @@ -1755,11 +1755,7 @@ void php_shutdown_stream_hashes(void) FG(wrapper_logged_errors) = NULL; } - if (FG(wrapper_stored_errors)) { - zend_hash_destroy(FG(wrapper_stored_errors)); - efree(FG(wrapper_stored_errors)); - FG(wrapper_stored_errors) = NULL; - } + php_stream_error_state_cleanup(); } zend_result php_init_stream_wrappers(int module_number) From c8784a8b493100f4bdfac5bff5ad2c3ff7385085 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Sun, 28 Dec 2025 17:31:44 +0100 Subject: [PATCH 43/68] stream: clean up and optimize wrapper errors --- main/streams/stream_errors.c | 627 ++++++++++++++++------------------- 1 file changed, 291 insertions(+), 336 deletions(-) diff --git a/main/streams/stream_errors.c b/main/streams/stream_errors.c index 5e17f6aa49146..78c10b491deb6 100644 --- a/main/streams/stream_errors.c +++ b/main/streams/stream_errors.c @@ -164,7 +164,7 @@ PHPAPI void php_stream_error_state_cleanup(void) FG(stream_error_state).current_operation = op->parent; php_stream_error_operation_free(op); } - + /* Clear stored errors */ php_stream_stored_error *stored = FG(stream_error_state).stored_errors; while (stored) { @@ -173,7 +173,7 @@ PHPAPI void php_stream_error_state_cleanup(void) efree(stored); stored = next; } - + FG(stream_error_state).stored_errors = NULL; FG(stream_error_state).stored_count = 0; FG(stream_error_state).operation_depth = 0; @@ -206,21 +206,16 @@ PHPAPI php_stream_error_operation *php_stream_error_operation_begin(php_stream_c } static void php_stream_error_add(StreamErrorCode code, const char *wrapper_name, - const char *message, const char *docref, const char *param, int severity, - bool terminating) + zend_string *message, const char *docref, char *param, int severity, bool terminating) { php_stream_error_operation *op = FG(stream_error_state).current_operation; - - if (!op) { - /* No operation context - skip */ - return; - } + ZEND_ASSERT(op != NULL); php_stream_error_entry *entry = emalloc(sizeof(php_stream_error_entry)); - entry->message = zend_string_init(message, strlen(message), 0); + entry->message = message; entry->code = code; entry->wrapper_name = wrapper_name ? estrdup(wrapper_name) : NULL; - entry->param = param ? estrdup(param) : NULL; + entry->param = param; entry->param = docref ? estrdup(docref) : NULL; entry->severity = severity; entry->terminating = terminating; @@ -296,10 +291,11 @@ static void php_stream_report_errors(php_stream_context *context, php_stream_err php_stream_error_entry *entry = op->first_error; while (entry) { if (entry->param) { - php_error_docref1( - entry->docref, entry->param, entry->severity, "%s", ZSTR_VAL(entry->message)); + php_error_docref1(entry->docref, entry->param, entry->severity, "%s", + ZSTR_VAL(entry->message)); } else { - php_error_docref(entry->docref, entry->severity, "%s", ZSTR_VAL(entry->message)); + php_error_docref( + entry->docref, entry->severity, "%s", ZSTR_VAL(entry->message)); } entry = entry->next; } @@ -460,7 +456,7 @@ PHPAPI void php_stream_error_operation_abort(void) static void php_stream_wrapper_error_internal(const char *wrapper_name, php_stream_context *context, const char *docref, int options, int severity, bool terminating, int code, char *param, - const char *message) + zend_string *message) { /* If not in an operation, create one */ bool implicit_operation = (FG(stream_error_state).current_operation == NULL); @@ -478,335 +474,299 @@ static void php_stream_wrapper_error_internal(const char *wrapper_name, php_stre } PHPAPI void php_stream_wrapper_error_with_name(const char *wrapper_name, - php_stream_context *context, const char *docref, int options, int severity, - bool terminating, int code, const char *fmt, ...) + php_stream_context *context, const char *docref, int options, int severity, + bool terminating, int code, const char *fmt, ...) { - if (!(options & REPORT_ERRORS)) { - return; - } - - va_list args; - va_start(args, fmt); - - char *message = NULL; - vspprintf(&message, 0, fmt, args); - va_end(args); - - php_stream_wrapper_error_internal( - wrapper_name, context, docref, options, severity, terminating, code, NULL, message); - - efree(message); + if (!(options & REPORT_ERRORS)) { + return; + } + + va_list args; + va_start(args, fmt); + zend_string *message = vstrpprintf(0, fmt, args); + va_end(args); + + php_stream_wrapper_error_internal( + wrapper_name, context, docref, options, severity, terminating, code, NULL, message); } -PHPAPI void php_stream_wrapper_error(php_stream_wrapper *wrapper, - php_stream_context *context, const char *docref, int options, - int severity, bool terminating, int code, const char *fmt, ...) +PHPAPI void php_stream_wrapper_error(php_stream_wrapper *wrapper, php_stream_context *context, + const char *docref, int options, int severity, bool terminating, int code, const char *fmt, + ...) { - if (!(options & REPORT_ERRORS)) { - return; - } - - va_list args; - va_start(args, fmt); - - char *message = NULL; - vspprintf(&message, 0, fmt, args); - va_end(args); - - const char *wrapper_name = PHP_STREAM_ERROR_WRAPPER_NAME(wrapper); - - php_stream_wrapper_error_internal( - wrapper_name, context, docref, options, severity, terminating, code, NULL, message); - - efree(message); + if (!(options & REPORT_ERRORS)) { + return; + } + + va_list args; + va_start(args, fmt); + zend_string *message = vstrpprintf(0, fmt, args); + va_end(args); + + const char *wrapper_name = PHP_STREAM_ERROR_WRAPPER_NAME(wrapper); + + php_stream_wrapper_error_internal( + wrapper_name, context, docref, options, severity, terminating, code, NULL, message); } -PHPAPI void php_stream_wrapper_error_param(php_stream_wrapper *wrapper, - php_stream_context *context, const char *docref, int options, - int severity, bool terminating, int code, const char *param, - const char *fmt, ...) +PHPAPI void php_stream_wrapper_error_param(php_stream_wrapper *wrapper, php_stream_context *context, + const char *docref, int options, int severity, bool terminating, int code, + const char *param, const char *fmt, ...) { - if (!(options & REPORT_ERRORS)) { - return; - } - - va_list args; - va_start(args, fmt); - - char *message = NULL; - vspprintf(&message, 0, fmt, args); - va_end(args); - - const char *wrapper_name = PHP_STREAM_ERROR_WRAPPER_NAME(wrapper); - char *param_copy = param ? estrdup(param) : NULL; - - php_stream_wrapper_error_internal( - wrapper_name, context, docref, options, severity, terminating, code, param_copy, message); - - efree(message); + if (!(options & REPORT_ERRORS)) { + return; + } + + va_list args; + va_start(args, fmt); + zend_string *message = vstrpprintf(0, fmt, args); + va_end(args); + + const char *wrapper_name = PHP_STREAM_ERROR_WRAPPER_NAME(wrapper); + char *param_copy = param ? estrdup(param) : NULL; + + php_stream_wrapper_error_internal(wrapper_name, context, docref, options, severity, terminating, + code, param_copy, message); } PHPAPI void php_stream_wrapper_error_param2(php_stream_wrapper *wrapper, - php_stream_context *context, const char *docref, int options, - int severity, bool terminating, int code, const char *param1, - const char *param2, const char *fmt, ...) + php_stream_context *context, const char *docref, int options, int severity, + bool terminating, int code, const char *param1, const char *param2, const char *fmt, ...) { - if (!(options & REPORT_ERRORS)) { - return; - } - - char *combined_param; - spprintf(&combined_param, 0, "%s,%s", param1, param2); - - va_list args; - va_start(args, fmt); - - char *message = NULL; - vspprintf(&message, 0, fmt, args); - va_end(args); - - const char *wrapper_name = PHP_STREAM_ERROR_WRAPPER_NAME(wrapper); - - php_stream_wrapper_error_internal( - wrapper_name, context, docref, options, severity, terminating, code, combined_param, message); - - efree(message); + if (!(options & REPORT_ERRORS)) { + return; + } + + char *combined_param; + spprintf(&combined_param, 0, "%s,%s", param1, param2); + + va_list args; + va_start(args, fmt); + zend_string *message = vstrpprintf(0, fmt, args); + va_end(args); + + const char *wrapper_name = PHP_STREAM_ERROR_WRAPPER_NAME(wrapper); + + php_stream_wrapper_error_internal(wrapper_name, context, docref, options, severity, terminating, + code, combined_param, message); } /* Stream error reporting - delegates to wrapper errors */ -PHPAPI void php_stream_error(php_stream *stream, const char *docref, - int severity, bool terminating, int code, const char *fmt, ...) +PHPAPI void php_stream_error(php_stream *stream, const char *docref, int severity, bool terminating, + int code, const char *fmt, ...) { - va_list args; - va_start(args, fmt); - - char *message = NULL; - vspprintf(&message, 0, fmt, args); - va_end(args); - - const char *wrapper_name = stream->wrapper - ? stream->wrapper->wops->label - : "stream"; - - php_stream_context *context = PHP_STREAM_CONTEXT(stream); - - /* Just call the wrapper error function */ - php_stream_wrapper_error_internal( - wrapper_name, - context, - docref, - REPORT_ERRORS, - severity, - terminating, - code, - NULL, - message - ); - - efree(message); + va_list args; + va_start(args, fmt); + + zend_string *message = vstrpprintf(0, fmt, args); + va_end(args); + + const char *wrapper_name = stream->wrapper ? stream->wrapper->wops->label : "stream"; + + php_stream_context *context = PHP_STREAM_CONTEXT(stream); + + /* Just call the wrapper error function */ + php_stream_wrapper_error_internal(wrapper_name, context, docref, REPORT_ERRORS, severity, + terminating, code, NULL, message); } /* Legacy wrapper error logging */ static void php_stream_error_entry_dtor_legacy(void *error) { - php_stream_error_entry *entry = *(php_stream_error_entry **) error; - zend_string_release(entry->message); - efree(entry->wrapper_name); - efree(entry->param); + php_stream_error_entry *entry = *(php_stream_error_entry **) error; + zend_string_release(entry->message); + efree(entry->wrapper_name); + efree(entry->param); efree(entry->docref); - efree(entry); + efree(entry); } static void php_stream_error_list_dtor(zval *item) { - zend_llist *list = (zend_llist *) Z_PTR_P(item); - zend_llist_destroy(list); - efree(list); + zend_llist *list = (zend_llist *) Z_PTR_P(item); + zend_llist_destroy(list); + efree(list); } static void php_stream_wrapper_log_store_error(zend_string *message, int code, - const char *wrapper_name, const char *param, int severity, bool terminating) + const char *wrapper_name, const char *param, int severity, bool terminating) { - char *param_copy = param ? estrdup(param) : NULL; - - php_stream_error_entry *entry = emalloc(sizeof(php_stream_error_entry)); - entry->message = zend_string_copy(message); - entry->code = code; - entry->wrapper_name = wrapper_name ? estrdup(wrapper_name) : NULL; - entry->param = param_copy; - entry->severity = severity; - entry->terminating = terminating; - entry->next = NULL; - - if (!FG(wrapper_logged_errors)) { - ALLOC_HASHTABLE(FG(wrapper_logged_errors)); - zend_hash_init(FG(wrapper_logged_errors), 8, NULL, php_stream_error_list_dtor, 0); - } - - zend_llist *list = zend_hash_str_find_ptr( - FG(wrapper_logged_errors), wrapper_name, strlen(wrapper_name)); - - if (!list) { - zend_llist new_list; - zend_llist_init(&new_list, sizeof(php_stream_error_entry *), - php_stream_error_entry_dtor_legacy, 0); - list = zend_hash_str_update_mem(FG(wrapper_logged_errors), wrapper_name, - strlen(wrapper_name), &new_list, sizeof(new_list)); - } - - zend_llist_add_element(list, &entry); + char *param_copy = param ? estrdup(param) : NULL; + + php_stream_error_entry *entry = emalloc(sizeof(php_stream_error_entry)); + entry->message = message; + entry->code = code; + entry->wrapper_name = wrapper_name ? estrdup(wrapper_name) : NULL; + entry->param = param_copy; + entry->severity = severity; + entry->terminating = terminating; + entry->next = NULL; + + if (!FG(wrapper_logged_errors)) { + ALLOC_HASHTABLE(FG(wrapper_logged_errors)); + zend_hash_init(FG(wrapper_logged_errors), 8, NULL, php_stream_error_list_dtor, 0); + } + + zend_llist *list + = zend_hash_str_find_ptr(FG(wrapper_logged_errors), wrapper_name, strlen(wrapper_name)); + + if (!list) { + zend_llist new_list; + zend_llist_init( + &new_list, sizeof(php_stream_error_entry *), php_stream_error_entry_dtor_legacy, 0); + list = zend_hash_str_update_mem(FG(wrapper_logged_errors), wrapper_name, + strlen(wrapper_name), &new_list, sizeof(new_list)); + } + + zend_llist_add_element(list, &entry); } static void php_stream_wrapper_log_error_internal(const php_stream_wrapper *wrapper, - php_stream_context *context, int options, int severity, bool terminating, - int code, char *param, const char *fmt, va_list args) + php_stream_context *context, int options, int severity, bool terminating, int code, + char *param, const char *fmt, va_list args) { - zend_string *message = vstrpprintf(0, fmt, args); - const char *wrapper_name = PHP_STREAM_ERROR_WRAPPER_NAME(wrapper); - - if (options & REPORT_ERRORS) { - /* Report immediately */ - php_stream_wrapper_error_internal( - wrapper_name, context, NULL, options, severity, terminating, code, param, ZSTR_VAL(message)); - } else { - /* Store for later display */ - php_stream_wrapper_log_store_error(message, code, wrapper_name, param, severity, terminating); - } - - zend_string_release(message); + zend_string *message = vstrpprintf(0, fmt, args); + const char *wrapper_name = PHP_STREAM_ERROR_WRAPPER_NAME(wrapper); + + if (options & REPORT_ERRORS) { + /* Report immediately */ + php_stream_wrapper_error_internal( + wrapper_name, context, NULL, options, severity, terminating, code, param, message); + } else { + /* Store for later display */ + php_stream_wrapper_log_store_error( + message, code, wrapper_name, param, severity, terminating); + } } PHPAPI void php_stream_wrapper_log_error(const php_stream_wrapper *wrapper, - php_stream_context *context, int options, int severity, bool terminating, - int code, const char *fmt, ...) + php_stream_context *context, int options, int severity, bool terminating, int code, + const char *fmt, ...) { - va_list args; - va_start(args, fmt); - php_stream_wrapper_log_error_internal( - wrapper, context, options, severity, terminating, code, NULL, fmt, args); - va_end(args); + va_list args; + va_start(args, fmt); + php_stream_wrapper_log_error_internal( + wrapper, context, options, severity, terminating, code, NULL, fmt, args); + va_end(args); } PHPAPI void php_stream_wrapper_log_error_param(const php_stream_wrapper *wrapper, - php_stream_context *context, int options, int severity, bool terminating, - int code, const char *param, const char *fmt, ...) + php_stream_context *context, int options, int severity, bool terminating, int code, + const char *param, const char *fmt, ...) { - va_list args; - va_start(args, fmt); - char *param_copy = param ? estrdup(param) : NULL; - php_stream_wrapper_log_error_internal( - wrapper, context, options, severity, terminating, code, param_copy, fmt, args); - va_end(args); + va_list args; + va_start(args, fmt); + char *param_copy = param ? estrdup(param) : NULL; + php_stream_wrapper_log_error_internal( + wrapper, context, options, severity, terminating, code, param_copy, fmt, args); + va_end(args); } static zend_llist *php_stream_get_wrapper_errors_list(const char *wrapper_name) { - if (!FG(wrapper_logged_errors)) { - return NULL; - } - return (zend_llist *) zend_hash_str_find_ptr( - FG(wrapper_logged_errors), wrapper_name, strlen(wrapper_name)); + if (!FG(wrapper_logged_errors)) { + return NULL; + } + return (zend_llist *) zend_hash_str_find_ptr( + FG(wrapper_logged_errors), wrapper_name, strlen(wrapper_name)); } PHPAPI void php_stream_display_wrapper_name_errors(const char *wrapper_name, - php_stream_context *context, int code, const char *path, const char *caption) + php_stream_context *context, int code, const char *path, const char *caption) { - char *msg; - char errstr[256]; - int free_msg = 0; - - if (EG(exception)) { - return; - } - - char *tmp = estrdup(path); - if (strcmp(wrapper_name, PHP_STREAM_ERROR_WRAPPER_DEFAULT_NAME)) { - zend_llist *err_list = php_stream_get_wrapper_errors_list(wrapper_name); - if (err_list) { - size_t l = 0; - int brlen; - int i; - int count = (int) zend_llist_count(err_list); - const char *br; - php_stream_error_entry **err_entry_p; - zend_llist_position pos; - - if (PG(html_errors)) { - brlen = 7; - br = "
\n"; - } else { - brlen = 1; - br = "\n"; - } - - for (err_entry_p = zend_llist_get_first_ex(err_list, &pos), i = 0; err_entry_p; - err_entry_p = zend_llist_get_next_ex(err_list, &pos), i++) { - l += ZSTR_LEN((*err_entry_p)->message); - if (i < count - 1) { - l += brlen; - } - } - msg = emalloc(l + 1); - msg[0] = '\0'; - for (err_entry_p = zend_llist_get_first_ex(err_list, &pos), i = 0; err_entry_p; - err_entry_p = zend_llist_get_next_ex(err_list, &pos), i++) { - strcat(msg, ZSTR_VAL((*err_entry_p)->message)); - if (i < count - 1) { - strcat(msg, br); - } - } - - free_msg = 1; - } else { - if (!strcmp(wrapper_name, php_plain_files_wrapper.wops->label)) { - msg = php_socket_strerror_s(errno, errstr, sizeof(errstr)); - } else { - msg = "operation failed"; - } - } - } else { - msg = "no suitable wrapper could be found"; - } - - php_strip_url_passwd(tmp); - - char *full_msg; - spprintf(&full_msg, 0, "%s: %s", caption, msg); - - php_stream_wrapper_error_internal( - wrapper_name, context, NULL, REPORT_ERRORS, E_WARNING, true, code, tmp, full_msg); - - efree(full_msg); - - if (free_msg) { - efree(msg); - } + char *msg; + char errstr[256]; + int free_msg = 0; + + if (EG(exception)) { + return; + } + + char *tmp = estrdup(path); + if (strcmp(wrapper_name, PHP_STREAM_ERROR_WRAPPER_DEFAULT_NAME)) { + zend_llist *err_list = php_stream_get_wrapper_errors_list(wrapper_name); + if (err_list) { + size_t l = 0; + int brlen; + int i; + int count = (int) zend_llist_count(err_list); + const char *br; + php_stream_error_entry **err_entry_p; + zend_llist_position pos; + + if (PG(html_errors)) { + brlen = 7; + br = "
\n"; + } else { + brlen = 1; + br = "\n"; + } + + for (err_entry_p = zend_llist_get_first_ex(err_list, &pos), i = 0; err_entry_p; + err_entry_p = zend_llist_get_next_ex(err_list, &pos), i++) { + l += ZSTR_LEN((*err_entry_p)->message); + if (i < count - 1) { + l += brlen; + } + } + msg = emalloc(l + 1); + msg[0] = '\0'; + for (err_entry_p = zend_llist_get_first_ex(err_list, &pos), i = 0; err_entry_p; + err_entry_p = zend_llist_get_next_ex(err_list, &pos), i++) { + strcat(msg, ZSTR_VAL((*err_entry_p)->message)); + if (i < count - 1) { + strcat(msg, br); + } + } + + free_msg = 1; + } else { + if (!strcmp(wrapper_name, php_plain_files_wrapper.wops->label)) { + msg = php_socket_strerror_s(errno, errstr, sizeof(errstr)); + } else { + msg = "operation failed"; + } + } + } else { + msg = "no suitable wrapper could be found"; + } + + php_strip_url_passwd(tmp); + + zend_string *message = strpprintf(0, "%s: %s", caption, msg); + + php_stream_wrapper_error_internal( + wrapper_name, context, NULL, REPORT_ERRORS, E_WARNING, true, code, tmp, message); + + if (free_msg) { + efree(msg); + } } PHPAPI void php_stream_display_wrapper_errors(php_stream_wrapper *wrapper, - php_stream_context *context, int code, const char *path, const char *caption) + php_stream_context *context, int code, const char *path, const char *caption) { - if (wrapper) { - const char *wrapper_name = PHP_STREAM_ERROR_WRAPPER_NAME(wrapper); - php_stream_display_wrapper_name_errors(wrapper_name, context, code, path, caption); - } + if (wrapper) { + const char *wrapper_name = PHP_STREAM_ERROR_WRAPPER_NAME(wrapper); + php_stream_display_wrapper_name_errors(wrapper_name, context, code, path, caption); + } } PHPAPI void php_stream_tidy_wrapper_name_error_log(const char *wrapper_name) { - if (FG(wrapper_logged_errors)) { - zend_hash_str_del(FG(wrapper_logged_errors), wrapper_name, strlen(wrapper_name)); - } + if (FG(wrapper_logged_errors)) { + zend_hash_str_del(FG(wrapper_logged_errors), wrapper_name, strlen(wrapper_name)); + } } PHPAPI void php_stream_tidy_wrapper_error_log(php_stream_wrapper *wrapper) { - if (wrapper) { - const char *wrapper_name = PHP_STREAM_ERROR_WRAPPER_NAME(wrapper); - php_stream_tidy_wrapper_name_error_log(wrapper_name); - } + if (wrapper) { + const char *wrapper_name = PHP_STREAM_ERROR_WRAPPER_NAME(wrapper); + php_stream_tidy_wrapper_name_error_log(wrapper_name); + } } /* StreamError object creation - no enum cache */ @@ -874,75 +834,70 @@ PHPAPI void php_stream_error_create_object(zval *zv, php_stream_error_entry *ent } } - /* StreamError methods */ PHP_METHOD(StreamError, hasCode) { - zval *search_code; - - ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_OBJECT_OF_CLASS(search_code, php_ce_stream_error_code) - ZEND_PARSE_PARAMETERS_END(); - - zval *current_error_zv = ZEND_THIS; - - while (Z_TYPE_P(current_error_zv) == IS_OBJECT) { - zval *code_zv = zend_read_property( - php_ce_stream_error, Z_OBJ_P(current_error_zv), - ZEND_STRL("code"), 1, NULL); - - /* Compare enum objects */ - if (Z_TYPE_P(code_zv) == IS_OBJECT && Z_OBJ_P(code_zv) == Z_OBJ_P(search_code)) { - RETURN_TRUE; - } - - /* Move to next error */ - current_error_zv = zend_read_property( - php_ce_stream_error, Z_OBJ_P(current_error_zv), - ZEND_STRL("next"), 1, NULL); - - if (Z_TYPE_P(current_error_zv) != IS_OBJECT) { - break; - } - } - - RETURN_FALSE; + zval *search_code; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_OBJECT_OF_CLASS(search_code, php_ce_stream_error_code) + ZEND_PARSE_PARAMETERS_END(); + + zval *current_error_zv = ZEND_THIS; + + while (Z_TYPE_P(current_error_zv) == IS_OBJECT) { + zval *code_zv = zend_read_property( + php_ce_stream_error, Z_OBJ_P(current_error_zv), ZEND_STRL("code"), 1, NULL); + + /* Compare enum objects */ + if (Z_TYPE_P(code_zv) == IS_OBJECT && Z_OBJ_P(code_zv) == Z_OBJ_P(search_code)) { + RETURN_TRUE; + } + + /* Move to next error */ + current_error_zv = zend_read_property( + php_ce_stream_error, Z_OBJ_P(current_error_zv), ZEND_STRL("next"), 1, NULL); + + if (Z_TYPE_P(current_error_zv) != IS_OBJECT) { + break; + } + } + + RETURN_FALSE; } PHP_METHOD(StreamError, count) { - ZEND_PARSE_PARAMETERS_NONE(); - - zend_long count = 1; - zval *current_error_zv = ZEND_THIS; - - while (1) { - current_error_zv = zend_read_property( - php_ce_stream_error, Z_OBJ_P(current_error_zv), - ZEND_STRL("next"), 1, NULL); - - if (Z_TYPE_P(current_error_zv) != IS_OBJECT) { - break; - } - - count++; - } - - RETURN_LONG(count); + ZEND_PARSE_PARAMETERS_NONE(); + + zend_long count = 1; + zval *current_error_zv = ZEND_THIS; + + while (1) { + current_error_zv = zend_read_property( + php_ce_stream_error, Z_OBJ_P(current_error_zv), ZEND_STRL("next"), 1, NULL); + + if (Z_TYPE_P(current_error_zv) != IS_OBJECT) { + break; + } + + count++; + } + + RETURN_LONG(count); } /* StreamException methods */ PHP_METHOD(StreamException, getError) { - ZEND_PARSE_PARAMETERS_NONE(); - - zval *error = zend_read_property( - php_ce_stream_exception, Z_OBJ_P(ZEND_THIS), - ZEND_STRL("error"), 1, NULL); - - RETURN_COPY(error); + ZEND_PARSE_PARAMETERS_NONE(); + + zval *error = zend_read_property( + php_ce_stream_exception, Z_OBJ_P(ZEND_THIS), ZEND_STRL("error"), 1, NULL); + + RETURN_COPY(error); } /* StreamErrorCode helper */ From 3169e80831f75ca1823970a8819e47d984f32ecc Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Sun, 28 Dec 2025 18:04:22 +0100 Subject: [PATCH 44/68] stream: fix test names --- ...de_helpers copy.phpt => stream_errors_error_code_helpers.phpt} | 0 ...error_has_code copy.phpt => stream_errors_error_has_code.phpt} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename ext/standard/tests/streams/{stream_errors_error_code_helpers copy.phpt => stream_errors_error_code_helpers.phpt} (100%) rename ext/standard/tests/streams/{stream_errors_error_has_code copy.phpt => stream_errors_error_has_code.phpt} (100%) diff --git a/ext/standard/tests/streams/stream_errors_error_code_helpers copy.phpt b/ext/standard/tests/streams/stream_errors_error_code_helpers.phpt similarity index 100% rename from ext/standard/tests/streams/stream_errors_error_code_helpers copy.phpt rename to ext/standard/tests/streams/stream_errors_error_code_helpers.phpt diff --git a/ext/standard/tests/streams/stream_errors_error_has_code copy.phpt b/ext/standard/tests/streams/stream_errors_error_has_code.phpt similarity index 100% rename from ext/standard/tests/streams/stream_errors_error_has_code copy.phpt rename to ext/standard/tests/streams/stream_errors_error_has_code.phpt From 98bd9f7f49fecb468951658071b1545d36efad62 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Sun, 28 Dec 2025 18:04:40 +0100 Subject: [PATCH 45/68] stream: fix docref initialization for stream errors --- main/streams/stream_errors.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/streams/stream_errors.c b/main/streams/stream_errors.c index 78c10b491deb6..3c5c49b9300c7 100644 --- a/main/streams/stream_errors.c +++ b/main/streams/stream_errors.c @@ -216,7 +216,7 @@ static void php_stream_error_add(StreamErrorCode code, const char *wrapper_name, entry->code = code; entry->wrapper_name = wrapper_name ? estrdup(wrapper_name) : NULL; entry->param = param; - entry->param = docref ? estrdup(docref) : NULL; + entry->docref = docref ? estrdup(docref) : NULL; entry->severity = severity; entry->terminating = terminating; entry->next = NULL; From 84d370c2b241d16fb86bf30bffd8f301edd05cd4 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Sun, 28 Dec 2025 20:12:11 +0100 Subject: [PATCH 46/68] stream: optimize error operation handling --- main/streams/php_stream_errors.h | 11 ++- main/streams/stream_errors.c | 130 ++++++++++++++++++++++++------- 2 files changed, 110 insertions(+), 31 deletions(-) diff --git a/main/streams/php_stream_errors.h b/main/streams/php_stream_errors.h index 783e9b5150e3f..ded43ce29a642 100644 --- a/main/streams/php_stream_errors.h +++ b/main/streams/php_stream_errors.h @@ -35,7 +35,9 @@ BEGIN_EXTERN_C() #define PHP_STREAM_ERROR_STORE_ALL 4 /* Maximum operation nesting depth */ -#define PHP_STREAM_ERROR_MAX_DEPTH 100 +#define PHP_STREAM_ERROR_MAX_DEPTH 1000 +/* Operations pool size to prevent extra allocations */ +#define PHP_STREAM_ERROR_OPERATION_POOL_SIZE 8 /* Error code ranges */ #define STREAM_ERROR_CODE_IO_START 10 @@ -194,11 +196,18 @@ typedef struct { /* List of completed/stored operations (most recent first) */ php_stream_stored_error *stored_errors; uint32_t stored_count; + /* Pre-allocated operation pool */ + php_stream_error_operation operation_pool[PHP_STREAM_ERROR_OPERATION_POOL_SIZE]; + /* Overflow operations (for deep nesting beyond pool size) */ + php_stream_error_operation *overflow_operations; + uint32_t overflow_capacity; } php_stream_error_state; /* Error operation management */ PHPAPI php_stream_error_operation *php_stream_error_operation_begin(php_stream_context *context); PHPAPI void php_stream_error_operation_end(php_stream_context *context); +PHPAPI php_stream_error_operation *php_stream_error_operation_begin_for_stream(php_stream *stream); +PHPAPI void php_stream_error_operation_end_for_stream(php_stream *stream); PHPAPI void php_stream_error_operation_abort(void); /* State cleanup function */ diff --git a/main/streams/stream_errors.c b/main/streams/stream_errors.c index 3c5c49b9300c7..3b2546f730d09 100644 --- a/main/streams/stream_errors.c +++ b/main/streams/stream_errors.c @@ -158,15 +158,25 @@ static void php_stream_error_operation_free(php_stream_error_operation *op) /* Cleanup function for request shutdown */ PHPAPI void php_stream_error_state_cleanup(void) { - /* Clear active operations (shouldn't normally have any, but clean up just in case) */ - while (FG(stream_error_state).current_operation) { - php_stream_error_operation *op = FG(stream_error_state).current_operation; - FG(stream_error_state).current_operation = op->parent; - php_stream_error_operation_free(op); + php_stream_error_state *state = &FG(stream_error_state); + + /* Clear active operations */ + while (state->current_operation) { + php_stream_error_operation *op = state->current_operation; + state->current_operation = op->parent; + + /* Free errors */ + php_stream_error_entry_free(op->first_error); + + /* Reset operation */ + op->first_error = NULL; + op->last_error = NULL; + op->error_count = 0; + op->parent = NULL; } /* Clear stored errors */ - php_stream_stored_error *stored = FG(stream_error_state).stored_errors; + php_stream_stored_error *stored = state->stored_errors; while (stored) { php_stream_stored_error *next = stored->next; php_stream_error_entry_free(stored->first_error); @@ -174,37 +184,72 @@ PHPAPI void php_stream_error_state_cleanup(void) stored = next; } - FG(stream_error_state).stored_errors = NULL; - FG(stream_error_state).stored_count = 0; - FG(stream_error_state).operation_depth = 0; -} + state->stored_errors = NULL; + state->stored_count = 0; + state->operation_depth = 0; + /* Free overflow operations array */ + if (state->overflow_operations) { + efree(state->overflow_operations); + state->overflow_operations = NULL; + state->overflow_capacity = 0; + } +} /* Error operation stack management */ PHPAPI php_stream_error_operation *php_stream_error_operation_begin(php_stream_context *context) { + php_stream_error_state *state = &FG(stream_error_state); + /* Check depth limit */ - if (FG(stream_error_state).operation_depth >= PHP_STREAM_ERROR_MAX_DEPTH) { + if (state->operation_depth >= PHP_STREAM_ERROR_MAX_DEPTH) { php_error_docref(NULL, E_WARNING, "Stream error operation depth exceeded (%u), possible infinite recursion", - FG(stream_error_state).operation_depth); + state->operation_depth); return NULL; } - /* Create new operation with empty error list */ - php_stream_error_operation *op = emalloc(sizeof(php_stream_error_operation)); + php_stream_error_operation *op; + + /* Try to use pre-allocated pool first */ + if (state->operation_depth < PHP_STREAM_ERROR_OPERATION_POOL_SIZE) { + op = &state->operation_pool[state->operation_depth]; + } else { + /* Need overflow allocation */ + uint32_t overflow_index = state->operation_depth - PHP_STREAM_ERROR_OPERATION_POOL_SIZE; + + /* Grow overflow array if needed */ + if (overflow_index >= state->overflow_capacity) { + uint32_t new_capacity + = state->overflow_capacity == 0 ? 8 : state->overflow_capacity * 2; + php_stream_error_operation *new_overflow = erealloc( + state->overflow_operations, sizeof(php_stream_error_operation) * new_capacity); + state->overflow_operations = new_overflow; + state->overflow_capacity = new_capacity; + } + + op = &state->overflow_operations[overflow_index]; + } + + /* Initialize operation */ op->first_error = NULL; op->last_error = NULL; op->error_count = 0; - op->parent = FG(stream_error_state).current_operation; + op->parent = state->current_operation; /* Push onto stack */ - FG(stream_error_state).current_operation = op; - FG(stream_error_state).operation_depth++; + state->current_operation = op; + state->operation_depth++; return op; } +PHPAPI php_stream_error_operation *php_stream_error_operation_begin_for_stream(php_stream *stream) +{ + /* Don't fetch context yet - will be fetched in _end_for_stream if needed */ + return php_stream_error_operation_begin(NULL); +} + static void php_stream_error_add(StreamErrorCode code, const char *wrapper_name, zend_string *message, const char *docref, char *param, int severity, bool terminating) { @@ -334,15 +379,16 @@ static void php_stream_report_errors(php_stream_context *context, php_stream_err PHPAPI void php_stream_error_operation_end(php_stream_context *context) { - php_stream_error_operation *op = FG(stream_error_state).current_operation; + php_stream_error_state *state = &FG(stream_error_state); + php_stream_error_operation *op = state->current_operation; if (!op) { return; } /* Pop from stack */ - FG(stream_error_state).current_operation = op->parent; - FG(stream_error_state).operation_depth--; + state->current_operation = op->parent; + state->operation_depth--; /* Process errors if we have any */ if (op->error_count > 0) { @@ -359,8 +405,6 @@ PHPAPI void php_stream_error_operation_end(php_stream_context *context) if (store_mode == PHP_STREAM_ERROR_STORE_NONE) { /* Free all errors */ php_stream_error_entry_free(op->first_error); - op->first_error = NULL; - op->last_error = NULL; } else { /* Filter and store */ php_stream_error_entry *entry = op->first_error; @@ -408,7 +452,6 @@ PHPAPI void php_stream_error_operation_end(php_stream_context *context) efree(entry->param); efree(entry); - /* Don't update prev */ entry = next; continue; } @@ -421,21 +464,48 @@ PHPAPI void php_stream_error_operation_end(php_stream_context *context) if (to_store_first) { php_stream_stored_error *stored = emalloc(sizeof(php_stream_stored_error)); stored->first_error = to_store_first; - stored->next = FG(stream_error_state).stored_errors; + stored->next = state->stored_errors; - FG(stream_error_state).stored_errors = stored; - FG(stream_error_state).stored_count++; + state->stored_errors = stored; + state->stored_count++; } /* Free any remaining errors not moved to storage */ php_stream_error_entry_free(op->first_error); - op->first_error = NULL; - op->last_error = NULL; } } - /* Free operation structure */ - efree(op); + /* Reset operation for reuse (don't free if from pool or overflow) */ + op->first_error = NULL; + op->last_error = NULL; + op->error_count = 0; + op->parent = NULL; +} + +PHPAPI void php_stream_error_operation_end_for_stream(php_stream *stream) +{ + php_stream_error_state *state = &FG(stream_error_state); + php_stream_error_operation *op = state->current_operation; + + if (!op) { + return; + } + + /* Fast path: no errors - just pop and return */ + if (op->error_count == 0) { + state->current_operation = op->parent; + state->operation_depth--; + + /* Reset operation for reuse */ + op->first_error = NULL; + op->last_error = NULL; + op->parent = NULL; + return; + } + + /* Slow path: have errors - fetch context and process */ + php_stream_context *context = PHP_STREAM_CONTEXT(stream); + php_stream_error_operation_end(context); } PHPAPI void php_stream_error_operation_abort(void) From dbfbcaea399d41e39212ee2cc85962bf2b517609 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Mon, 29 Dec 2025 00:21:12 +0100 Subject: [PATCH 47/68] stream: modify error begin and end api --- main/streams/php_stream_errors.h | 3 +-- main/streams/stream_errors.c | 8 +------- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/main/streams/php_stream_errors.h b/main/streams/php_stream_errors.h index ded43ce29a642..d34e549632a1a 100644 --- a/main/streams/php_stream_errors.h +++ b/main/streams/php_stream_errors.h @@ -204,9 +204,8 @@ typedef struct { } php_stream_error_state; /* Error operation management */ -PHPAPI php_stream_error_operation *php_stream_error_operation_begin(php_stream_context *context); +PHPAPI php_stream_error_operation *php_stream_error_operation_begin(void); PHPAPI void php_stream_error_operation_end(php_stream_context *context); -PHPAPI php_stream_error_operation *php_stream_error_operation_begin_for_stream(php_stream *stream); PHPAPI void php_stream_error_operation_end_for_stream(php_stream *stream); PHPAPI void php_stream_error_operation_abort(void); diff --git a/main/streams/stream_errors.c b/main/streams/stream_errors.c index 3b2546f730d09..a54a0c62f290d 100644 --- a/main/streams/stream_errors.c +++ b/main/streams/stream_errors.c @@ -197,7 +197,7 @@ PHPAPI void php_stream_error_state_cleanup(void) } /* Error operation stack management */ -PHPAPI php_stream_error_operation *php_stream_error_operation_begin(php_stream_context *context) +PHPAPI php_stream_error_operation *php_stream_error_operation_begin(void) { php_stream_error_state *state = &FG(stream_error_state); @@ -244,12 +244,6 @@ PHPAPI php_stream_error_operation *php_stream_error_operation_begin(php_stream_c return op; } -PHPAPI php_stream_error_operation *php_stream_error_operation_begin_for_stream(php_stream *stream) -{ - /* Don't fetch context yet - will be fetched in _end_for_stream if needed */ - return php_stream_error_operation_begin(NULL); -} - static void php_stream_error_add(StreamErrorCode code, const char *wrapper_name, zend_string *message, const char *docref, char *param, int severity, bool terminating) { From bad3b38e0fc540a511ff55cd6100cb993e984a5f Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Mon, 29 Dec 2025 00:21:54 +0100 Subject: [PATCH 48/68] stream: add error begin and end to standard/file.c --- ext/standard/file.c | 139 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 113 insertions(+), 26 deletions(-) diff --git a/ext/standard/file.c b/ext/standard/file.c index 3b0112a0aad15..11ac70a5fcd55 100644 --- a/ext/standard/file.c +++ b/ext/standard/file.c @@ -223,7 +223,9 @@ PHP_FUNCTION(flock) Z_PARAM_ZVAL(wouldblock) ZEND_PARSE_PARAMETERS_END(); + php_stream_error_operation_begin(); php_flock_common(stream, operation, 2, wouldblock, return_value); + php_stream_error_operation_end_for_stream(stream); } /* }}} */ @@ -259,6 +261,8 @@ PHP_FUNCTION(get_meta_tags) RETURN_FALSE; } + php_stream_error_operation_begin(); + array_init(return_value); tok_last = TOK_EOF; @@ -370,6 +374,8 @@ PHP_FUNCTION(get_meta_tags) if (value) efree(value); if (name) efree(name); php_stream_close(md.stream); + + php_stream_error_operation_end_for_stream(md.stream); } /* }}} */ @@ -404,12 +410,13 @@ PHP_FUNCTION(file_get_contents) RETURN_THROWS(); } + php_stream_error_operation_begin(); context = php_stream_context_from_zval(zcontext, 0); - stream = php_stream_open_wrapper_ex(filename, "rb", (use_include_path ? USE_PATH : 0) | REPORT_ERRORS, NULL, context); if (!stream) { + php_stream_error_operation_end(context); RETURN_FALSE; } @@ -422,6 +429,7 @@ PHP_FUNCTION(file_get_contents) if (offset != 0 && php_stream_seek(stream, offset, ((offset > 0) ? SEEK_SET : SEEK_END)) < 0) { php_error_docref(NULL, E_WARNING, "Failed to seek to position " ZEND_LONG_FMT " in the stream", offset); php_stream_close(stream); + php_stream_error_operation_end(context); RETURN_FALSE; } @@ -432,6 +440,7 @@ PHP_FUNCTION(file_get_contents) } php_stream_close(stream); + php_stream_error_operation_end(context); } /* }}} */ @@ -461,6 +470,7 @@ PHP_FUNCTION(file_put_contents) php_stream_from_zval(srcstream, data); } + php_stream_error_operation_begin(); context = php_stream_context_from_zval(zcontext, flags & PHP_FILE_NO_DEFAULT_CONTEXT); if (flags & PHP_FILE_APPEND) { @@ -479,12 +489,14 @@ PHP_FUNCTION(file_put_contents) stream = php_stream_open_wrapper_ex(filename, mode, ((flags & PHP_FILE_USE_INCLUDE_PATH) ? USE_PATH : 0) | REPORT_ERRORS, NULL, context); if (stream == NULL) { + php_stream_error_operation_end(context); RETURN_FALSE; } if ((flags & LOCK_EX) && (!php_stream_supports_lock(stream) || php_stream_lock(stream, LOCK_EX))) { php_stream_close(stream); php_error_docref(NULL, E_WARNING, "Exclusive locks are not supported for this stream"); + php_stream_error_operation_end(context); RETURN_FALSE; } @@ -566,6 +578,7 @@ PHP_FUNCTION(file_put_contents) break; } php_stream_close(stream); + php_stream_error_operation_end(context); if (numbytes < 0) { RETURN_FALSE; @@ -611,10 +624,12 @@ PHP_FUNCTION(file) include_new_line = !(flags & PHP_FILE_IGNORE_NEW_LINES); skip_blank_lines = flags & PHP_FILE_SKIP_EMPTY_LINES; + php_stream_error_operation_begin(); context = php_stream_context_from_zval(zcontext, flags & PHP_FILE_NO_DEFAULT_CONTEXT); stream = php_stream_open_wrapper_ex(filename, "rb", (use_include_path ? USE_PATH : 0) | REPORT_ERRORS, NULL, context); if (!stream) { + php_stream_error_operation_end(context); RETURN_FALSE; } @@ -668,6 +683,7 @@ PHP_FUNCTION(file) } php_stream_close(stream); + php_stream_error_operation_end(context); } /* }}} */ @@ -707,7 +723,9 @@ PHP_FUNCTION(tmpfile) ZEND_PARSE_PARAMETERS_NONE(); + php_stream_error_operation_begin(); stream = php_stream_fopen_tmpfile(); + php_stream_error_operation_end_for_stream(stream); if (stream) { php_stream_to_zval(stream, return_value); @@ -735,9 +753,11 @@ PHP_FUNCTION(fopen) Z_PARAM_RESOURCE_OR_NULL(zcontext) ZEND_PARSE_PARAMETERS_END(); + php_stream_error_operation_begin(); context = php_stream_context_from_zval(zcontext, 0); stream = php_stream_open_wrapper_ex(filename, mode, (use_include_path ? USE_PATH : 0) | REPORT_ERRORS, NULL, context); + php_stream_error_operation_end(context); if (stream == NULL) { RETURN_FALSE; @@ -761,9 +781,11 @@ PHPAPI PHP_FUNCTION(fclose) RETURN_FALSE; } + php_stream_error_operation_begin(); php_stream_free(stream, PHP_STREAM_FREE_KEEP_RSRC | (stream->is_persistent ? PHP_STREAM_FREE_CLOSE_PERSISTENT : PHP_STREAM_FREE_CLOSE)); + php_stream_error_operation_end_for_stream(stream); RETURN_TRUE; } @@ -811,6 +833,7 @@ PHP_FUNCTION(popen) RETURN_FALSE; } + php_stream_error_operation_begin(); stream = php_stream_fopen_from_pipe(fp, mode); if (stream == NULL) { @@ -819,6 +842,7 @@ PHP_FUNCTION(popen) } else { php_stream_to_zval(stream, return_value); } + php_stream_error_operation_end_for_stream(stream); efree(posix_mode); } @@ -833,9 +857,11 @@ PHP_FUNCTION(pclose) PHP_Z_PARAM_STREAM(stream) ZEND_PARSE_PARAMETERS_END(); + php_stream_error_operation_begin(); FG(pclose_wait) = 1; zend_list_close(stream->res); FG(pclose_wait) = 0; + php_stream_error_operation_end_for_stream(stream); RETURN_LONG(FG(pclose_ret)); } /* }}} */ @@ -849,11 +875,13 @@ PHPAPI PHP_FUNCTION(feof) PHP_Z_PARAM_STREAM(stream) ZEND_PARSE_PARAMETERS_END(); + php_stream_error_operation_begin(); if (php_stream_eof(stream)) { - RETURN_TRUE; + RETVAL_TRUE; } else { - RETURN_FALSE; + RETVAL_FALSE; } + php_stream_error_operation_end_for_stream(stream); } /* }}} */ @@ -873,9 +901,11 @@ PHPAPI PHP_FUNCTION(fgets) Z_PARAM_LONG_OR_NULL(len, len_is_null) ZEND_PARSE_PARAMETERS_END(); + php_stream_error_operation_begin(); if (len_is_null) { /* ask streams to give us a buffer of an appropriate size */ buf = php_stream_get_line(stream, NULL, 0, &line_len); + php_stream_error_operation_end_for_stream(stream); if (buf == NULL) { RETURN_FALSE; } @@ -889,7 +919,9 @@ PHPAPI PHP_FUNCTION(fgets) } str = zend_string_alloc(len, 0); - if (php_stream_get_line(stream, ZSTR_VAL(str), len, &line_len) == NULL) { + buf = php_stream_get_line(stream, ZSTR_VAL(str), len, &line_len); + php_stream_error_operation_end_for_stream(stream); + if (buf == NULL) { zend_string_efree(str); RETURN_FALSE; } @@ -914,7 +946,9 @@ PHPAPI PHP_FUNCTION(fgetc) PHP_Z_PARAM_STREAM(stream) ZEND_PARSE_PARAMETERS_END(); + php_stream_error_operation_begin(); int result = php_stream_getc(stream); + php_stream_error_operation_end_for_stream(stream); if (result == EOF) { RETVAL_FALSE; @@ -933,7 +967,6 @@ PHP_FUNCTION(fscanf) zval *file_handle; char *buf, *format; size_t len; - void *what; ZEND_PARSE_PARAMETERS_START(2, -1) Z_PARAM_RESOURCE(file_handle) @@ -941,16 +974,18 @@ PHP_FUNCTION(fscanf) Z_PARAM_VARIADIC('*', args, argc) ZEND_PARSE_PARAMETERS_END(); - what = zend_fetch_resource2(Z_RES_P(file_handle), "File-Handle", php_file_le_stream(), php_file_le_pstream()); + php_stream *stream = zend_fetch_resource2(Z_RES_P(file_handle), "File-Handle", php_file_le_stream(), php_file_le_pstream()); - /* we can't do a ZEND_VERIFY_RESOURCE(what), otherwise we end up + /* we can't do a ZEND_VERIFY_RESOURCE(stream), otherwise we end up * with a leak if we have an invalid filehandle. This needs changing * if the code behind ZEND_VERIFY_RESOURCE changed. - cc */ - if (!what) { + if (!stream) { RETURN_THROWS(); } - buf = php_stream_get_line((php_stream *) what, NULL, 0, &len); + php_stream_error_operation_begin(); + buf = php_stream_get_line(stream, NULL, 0, &len); + php_stream_error_operation_end_for_stream(stream); if (buf == NULL) { RETURN_FALSE; } @@ -996,7 +1031,9 @@ PHPAPI PHP_FUNCTION(fwrite) RETURN_LONG(0); } + php_stream_error_operation_begin(); ret = php_stream_write(stream, input, num_bytes); + php_stream_error_operation_end_for_stream(stream); if (ret < 0) { RETURN_FALSE; } @@ -1015,8 +1052,9 @@ PHPAPI PHP_FUNCTION(fflush) PHP_Z_PARAM_STREAM(stream) ZEND_PARSE_PARAMETERS_END(); + php_stream_error_operation_begin(); ret = php_stream_flush(stream); - + php_stream_error_operation_end_for_stream(stream); RETURN_BOOL(!ret); } /* }}} */ @@ -1024,13 +1062,17 @@ PHPAPI PHP_FUNCTION(fflush) /* {{{ Rewind the position of a file pointer */ PHPAPI PHP_FUNCTION(rewind) { + int ret; php_stream *stream; ZEND_PARSE_PARAMETERS_START(1, 1) PHP_Z_PARAM_STREAM(stream) ZEND_PARSE_PARAMETERS_END(); - RETURN_BOOL(-1 != php_stream_rewind(stream)); + php_stream_error_operation_begin(); + ret = php_stream_rewind(stream); + php_stream_error_operation_end_for_stream(stream); + RETURN_BOOL(-1 != ret); } /* }}} */ @@ -1044,7 +1086,9 @@ PHPAPI PHP_FUNCTION(ftell) PHP_Z_PARAM_STREAM(stream) ZEND_PARSE_PARAMETERS_END(); + php_stream_error_operation_begin(); ret = php_stream_tell(stream); + php_stream_error_operation_end_for_stream(stream); if (ret == -1) { RETURN_FALSE; } @@ -1065,7 +1109,9 @@ PHPAPI PHP_FUNCTION(fseek) Z_PARAM_LONG(whence) ZEND_PARSE_PARAMETERS_END(); - RETURN_LONG(php_stream_seek(stream, offset, (int) whence)); + php_stream_error_operation_begin(); + RETVAL_LONG(php_stream_seek(stream, offset, (int) whence)); + php_stream_error_operation_end_for_stream(stream); } /* }}} */ @@ -1089,7 +1135,9 @@ PHP_FUNCTION(mkdir) context = php_stream_context_from_zval(zcontext, 0); - RETURN_BOOL(php_stream_mkdir(dir, (int)mode, (recursive ? PHP_STREAM_MKDIR_RECURSIVE : 0) | REPORT_ERRORS, context)); + php_stream_error_operation_begin(); + RETVAL_BOOL(php_stream_mkdir(dir, (int)mode, (recursive ? PHP_STREAM_MKDIR_RECURSIVE : 0) | REPORT_ERRORS, context)); + php_stream_error_operation_end(context); } /* }}} */ @@ -1109,7 +1157,9 @@ PHP_FUNCTION(rmdir) context = php_stream_context_from_zval(zcontext, 0); - RETURN_BOOL(php_stream_rmdir(dir, REPORT_ERRORS, context)); + php_stream_error_operation_begin(); + RETVAL_BOOL(php_stream_rmdir(dir, REPORT_ERRORS, context)); + php_stream_error_operation_end(context); } /* }}} */ @@ -1133,14 +1183,17 @@ PHP_FUNCTION(readfile) context = php_stream_context_from_zval(zcontext, 0); + php_stream_error_operation_begin(); stream = php_stream_open_wrapper_ex(filename, "rb", (use_include_path ? USE_PATH : 0) | REPORT_ERRORS, NULL, context); if (stream) { size = php_stream_passthru(stream); php_stream_close(stream); - RETURN_LONG(size); + RETVAL_LONG(size); + } else { + RETVAL_FALSE; } + php_stream_error_operation_end(context); - RETURN_FALSE; } /* }}} */ @@ -1182,7 +1235,9 @@ PHPAPI PHP_FUNCTION(fpassthru) PHP_Z_PARAM_STREAM(stream) ZEND_PARSE_PARAMETERS_END(); + php_stream_error_operation_begin(); size = php_stream_passthru(stream); + php_stream_error_operation_end_for_stream(stream); RETURN_LONG(size); } /* }}} */ @@ -1203,26 +1258,31 @@ PHP_FUNCTION(rename) Z_PARAM_RESOURCE_OR_NULL(zcontext) ZEND_PARSE_PARAMETERS_END(); + php_stream_error_operation_begin(); + context = php_stream_context_from_zval(zcontext, 0); + wrapper = php_stream_locate_url_wrapper(old_name, NULL, 0); if (!wrapper || !wrapper->wops) { php_error_docref(NULL, E_WARNING, "Unable to locate stream wrapper"); + php_stream_error_operation_end(context); RETURN_FALSE; } if (!wrapper->wops->rename) { php_error_docref(NULL, E_WARNING, "%s wrapper does not support renaming", wrapper->wops->label ? wrapper->wops->label : "Source"); + php_stream_error_operation_end(context); RETURN_FALSE; } if (wrapper != php_stream_locate_url_wrapper(new_name, NULL, 0)) { php_error_docref(NULL, E_WARNING, "Cannot rename a file across wrapper types"); + php_stream_error_operation_end(context); RETURN_FALSE; } - context = php_stream_context_from_zval(zcontext, 0); - - RETURN_BOOL(wrapper->wops->rename(wrapper, old_name, new_name, REPORT_ERRORS, context)); + RETVAL_BOOL(wrapper->wops->rename(wrapper, old_name, new_name, REPORT_ERRORS, context)); + php_stream_error_operation_end(context); } /* }}} */ @@ -1241,20 +1301,24 @@ PHP_FUNCTION(unlink) Z_PARAM_RESOURCE_OR_NULL(zcontext) ZEND_PARSE_PARAMETERS_END(); + php_stream_error_operation_begin(); context = php_stream_context_from_zval(zcontext, 0); wrapper = php_stream_locate_url_wrapper(filename, NULL, 0); if (!wrapper || !wrapper->wops) { php_error_docref(NULL, E_WARNING, "Unable to locate stream wrapper"); + php_stream_error_operation_end(context); RETURN_FALSE; } if (!wrapper->wops->unlink) { php_error_docref(NULL, E_WARNING, "%s does not allow unlinking", wrapper->wops->label ? wrapper->wops->label : "Wrapper"); + php_stream_error_operation_end(context); RETURN_FALSE; } - RETURN_BOOL(wrapper->wops->unlink(wrapper, filename, REPORT_ERRORS, context)); + RETVAL_BOOL(wrapper->wops->unlink(wrapper, filename, REPORT_ERRORS, context)); + php_stream_error_operation_end(context); } /* }}} */ @@ -1266,12 +1330,15 @@ PHP_FUNCTION(fsync) PHP_Z_PARAM_STREAM(stream) ZEND_PARSE_PARAMETERS_END(); + php_stream_error_operation_begin(); if (!php_stream_sync_supported(stream)) { php_error_docref(NULL, E_WARNING, "Can't fsync this stream!"); + php_stream_error_operation_end_for_stream(stream); RETURN_FALSE; } - RETURN_BOOL(php_stream_sync(stream, /* data_only */ 0) == 0); + RETVAL_BOOL(php_stream_sync(stream, /* data_only */ 0) == 0); + php_stream_error_operation_end_for_stream(stream); } PHP_FUNCTION(fdatasync) @@ -1282,12 +1349,15 @@ PHP_FUNCTION(fdatasync) PHP_Z_PARAM_STREAM(stream) ZEND_PARSE_PARAMETERS_END(); + php_stream_error_operation_begin(); if (!php_stream_sync_supported(stream)) { php_error_docref(NULL, E_WARNING, "Can't fsync this stream!"); + php_stream_error_operation_end_for_stream(stream); RETURN_FALSE; } - RETURN_BOOL(php_stream_sync(stream, /* data_only */ 1) == 0); + RETVAL_BOOL(php_stream_sync(stream, /* data_only */ 1) == 0); + php_stream_error_operation_end_for_stream(stream); } /* {{{ Truncate file to 'size' length */ @@ -1306,12 +1376,16 @@ PHP_FUNCTION(ftruncate) RETURN_THROWS(); } + php_stream_error_operation_begin(); + if (!php_stream_truncate_supported(stream)) { php_error_docref(NULL, E_WARNING, "Can't truncate this stream!"); + php_stream_error_operation_end_for_stream(stream); RETURN_FALSE; } - RETURN_BOOL(0 == php_stream_truncate_set_size(stream, size)); + RETVAL_BOOL(0 == php_stream_truncate_set_size(stream, size)); + php_stream_error_operation_end_for_stream(stream); } /* }}} */ PHPAPI void php_fstat(php_stream *stream, zval *return_value) @@ -1395,7 +1469,9 @@ PHP_FUNCTION(fstat) PHP_Z_PARAM_STREAM(stream) ZEND_PARSE_PARAMETERS_END(); + php_stream_error_operation_begin(); php_fstat(stream, return_value); + php_stream_error_operation_end_for_stream(stream); } /* }}} */ @@ -1414,13 +1490,16 @@ PHP_FUNCTION(copy) Z_PARAM_RESOURCE_OR_NULL(zcontext) ZEND_PARSE_PARAMETERS_END(); + php_stream_error_operation_begin(); + context = php_stream_context_from_zval(zcontext, 0); + if (php_stream_locate_url_wrapper(source, NULL, 0) == &php_plain_files_wrapper && php_check_open_basedir(source)) { + php_stream_error_operation_end(context); RETURN_FALSE; } - context = php_stream_context_from_zval(zcontext, 0); - - RETURN_BOOL(php_copy_file_ctx(source, target, 0, context) == SUCCESS); + RETVAL_BOOL(php_copy_file_ctx(source, target, 0, context) == SUCCESS); + php_stream_error_operation_end(context); } /* }}} */ @@ -1545,7 +1624,9 @@ PHPAPI PHP_FUNCTION(fread) RETURN_THROWS(); } + php_stream_error_operation_begin(); str = php_stream_read_to_str(stream, len); + php_stream_error_operation_end_for_stream(stream); if (!str) { RETURN_FALSE; } @@ -1664,7 +1745,9 @@ PHP_FUNCTION(fputcsv) RETURN_THROWS(); } + php_stream_error_operation_begin(); ret = php_fputcsv(stream, fields, delimiter, enclosure, escape_char, eol_str); + php_stream_error_operation_end_for_stream(stream); if (ret < 0) { RETURN_FALSE; } @@ -1797,19 +1880,23 @@ PHP_FUNCTION(fgetcsv) RETURN_THROWS(); } + php_stream_error_operation_begin(); if (len < 0) { if ((buf = php_stream_get_line(stream, NULL, 0, &buf_len)) == NULL) { + php_stream_error_operation_end_for_stream(stream); RETURN_FALSE; } } else { buf = emalloc(len + 1); if (php_stream_get_line(stream, buf, len + 1, &buf_len) == NULL) { efree(buf); + php_stream_error_operation_end_for_stream(stream); RETURN_FALSE; } } HashTable *values = php_fgetcsv(stream, delimiter, enclosure, escape_char, buf_len, buf); + php_stream_error_operation_end_for_stream(stream); if (values == NULL) { values = php_bc_fgetcsv_empty_line(); } From cfc1d6825211634b100be1977d131049ea319686 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Mon, 29 Dec 2025 12:08:32 +0100 Subject: [PATCH 49/68] stream: fix and refactore errors operation parent handling --- main/streams/php_stream_errors.h | 1 - main/streams/stream_errors.c | 62 ++++++++++++++++++++++++-------- 2 files changed, 47 insertions(+), 16 deletions(-) diff --git a/main/streams/php_stream_errors.h b/main/streams/php_stream_errors.h index d34e549632a1a..4d64e3905034a 100644 --- a/main/streams/php_stream_errors.h +++ b/main/streams/php_stream_errors.h @@ -180,7 +180,6 @@ typedef struct _php_stream_error_operation { php_stream_error_entry *first_error; php_stream_error_entry *last_error; uint32_t error_count; - struct _php_stream_error_operation *parent; } php_stream_error_operation; /* Stored completed operation */ diff --git a/main/streams/stream_errors.c b/main/streams/stream_errors.c index a54a0c62f290d..94578ab6341e3 100644 --- a/main/streams/stream_errors.c +++ b/main/streams/stream_errors.c @@ -137,6 +137,34 @@ static bool php_stream_has_terminating_error(php_stream_error_operation *op) return false; } +/* Helper to get operation at specific depth */ +static inline php_stream_error_operation *php_stream_get_operation_at_depth(uint32_t depth) +{ + php_stream_error_state *state = &FG(stream_error_state); + + if (depth < PHP_STREAM_ERROR_OPERATION_POOL_SIZE) { + return &state->operation_pool[depth]; + } else { + uint32_t overflow_index = depth - PHP_STREAM_ERROR_OPERATION_POOL_SIZE; + ZEND_ASSERT(overflow_index < state->overflow_capacity); + return &state->overflow_operations[overflow_index]; + } +} + +/* Helper to get parent operation */ +static inline php_stream_error_operation *php_stream_get_parent_operation(void) +{ + php_stream_error_state *state = &FG(stream_error_state); + + if (state->operation_depth <= 1) { + return NULL; + } + + return php_stream_get_operation_at_depth(state->operation_depth - 2); +} + +/* Clean up functions */ + static void php_stream_error_entry_free(php_stream_error_entry *entry) { while (entry) { @@ -155,7 +183,6 @@ static void php_stream_error_operation_free(php_stream_error_operation *op) efree(op); } -/* Cleanup function for request shutdown */ PHPAPI void php_stream_error_state_cleanup(void) { php_stream_error_state *state = &FG(stream_error_state); @@ -163,7 +190,8 @@ PHPAPI void php_stream_error_state_cleanup(void) /* Clear active operations */ while (state->current_operation) { php_stream_error_operation *op = state->current_operation; - state->current_operation = op->parent; + state->operation_depth--; + state->current_operation = php_stream_get_parent_operation(); /* Free errors */ php_stream_error_entry_free(op->first_error); @@ -172,7 +200,6 @@ PHPAPI void php_stream_error_state_cleanup(void) op->first_error = NULL; op->last_error = NULL; op->error_count = 0; - op->parent = NULL; } /* Clear stored errors */ @@ -195,6 +222,7 @@ PHPAPI void php_stream_error_state_cleanup(void) state->overflow_capacity = 0; } } + /* Error operation stack management */ PHPAPI php_stream_error_operation *php_stream_error_operation_begin(void) @@ -235,9 +263,8 @@ PHPAPI php_stream_error_operation *php_stream_error_operation_begin(void) op->first_error = NULL; op->last_error = NULL; op->error_count = 0; - op->parent = state->current_operation; - /* Push onto stack */ + /* Update stack state */ state->current_operation = op; state->operation_depth++; @@ -381,8 +408,8 @@ PHPAPI void php_stream_error_operation_end(php_stream_context *context) } /* Pop from stack */ - state->current_operation = op->parent; state->operation_depth--; + state->current_operation = php_stream_get_parent_operation(); /* Process errors if we have any */ if (op->error_count > 0) { @@ -444,6 +471,7 @@ PHPAPI void php_stream_error_operation_end(php_stream_context *context) zend_string_release(entry->message); efree(entry->wrapper_name); efree(entry->param); + efree(entry->docref); efree(entry); entry = next; @@ -469,11 +497,10 @@ PHPAPI void php_stream_error_operation_end(php_stream_context *context) } } - /* Reset operation for reuse (don't free if from pool or overflow) */ + /* Reset operation for reuse */ op->first_error = NULL; op->last_error = NULL; op->error_count = 0; - op->parent = NULL; } PHPAPI void php_stream_error_operation_end_for_stream(php_stream *stream) @@ -487,13 +514,12 @@ PHPAPI void php_stream_error_operation_end_for_stream(php_stream *stream) /* Fast path: no errors - just pop and return */ if (op->error_count == 0) { - state->current_operation = op->parent; state->operation_depth--; + state->current_operation = php_stream_get_parent_operation(); /* Reset operation for reuse */ op->first_error = NULL; op->last_error = NULL; - op->parent = NULL; return; } @@ -504,16 +530,22 @@ PHPAPI void php_stream_error_operation_end_for_stream(php_stream *stream) PHPAPI void php_stream_error_operation_abort(void) { - php_stream_error_operation *op = FG(stream_error_state).current_operation; + php_stream_error_state *state = &FG(stream_error_state); + php_stream_error_operation *op = state->current_operation; if (!op) { return; } - FG(stream_error_state).current_operation = op->parent; - FG(stream_error_state).operation_depth--; + /* Pop from stack */ + state->operation_depth--; + state->current_operation = php_stream_get_parent_operation(); - php_stream_error_operation_free(op); + /* Free errors and reset operation */ + php_stream_error_entry_free(op->first_error); + op->first_error = NULL; + op->last_error = NULL; + op->error_count = 0; } /* Wrapper error reporting */ @@ -525,7 +557,7 @@ static void php_stream_wrapper_error_internal(const char *wrapper_name, php_stre /* If not in an operation, create one */ bool implicit_operation = (FG(stream_error_state).current_operation == NULL); if (implicit_operation) { - php_stream_error_operation_begin(context); + php_stream_error_operation_begin(); } /* Add to current operation (or skip if no operation) */ From 39717a88db0e575e1619102b16816c6daf8bbc8c Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Mon, 29 Dec 2025 12:46:00 +0100 Subject: [PATCH 50/68] stream: fix incorrect stream error tests --- .../streams/stream_errors_error_code_helpers.phpt | 10 +++++----- .../tests/streams/stream_errors_invalid_types.phpt | 6 +++++- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/ext/standard/tests/streams/stream_errors_error_code_helpers.phpt b/ext/standard/tests/streams/stream_errors_error_code_helpers.phpt index c52bafb52c6f1..dc452e846fb4b 100644 --- a/ext/standard/tests/streams/stream_errors_error_code_helpers.phpt +++ b/ext/standard/tests/streams/stream_errors_error_code_helpers.phpt @@ -10,7 +10,7 @@ $context = stream_context_create([ ]); // Generate a network error -$stream = @fsockopen('invalid-host-12345.example.com', 80, $errno, $errstr, 1, $context); +$stream = fopen('php://nonexistent', 'r', false, $context); $error = stream_get_last_error(); if ($error) { @@ -22,7 +22,7 @@ if ($error) { ?> --EXPECTF-- -Is I/O error: %s -Is filesystem error: no -Is network error: %s -Is wrapper error: %s +Is I/O error: no +Is filesystem error: yes +Is network error: no +Is wrapper error: no diff --git a/ext/standard/tests/streams/stream_errors_invalid_types.phpt b/ext/standard/tests/streams/stream_errors_invalid_types.phpt index 22563920ed672..1b3ab5e8931e3 100644 --- a/ext/standard/tests/streams/stream_errors_invalid_types.phpt +++ b/ext/standard/tests/streams/stream_errors_invalid_types.phpt @@ -28,6 +28,10 @@ try { } ?> ---EXPECT-- +--EXPECTF-- + +Warning: fopen(php://nonexistent): Failed to open stream: operation failed in %s on line %d Caught TypeError for error_mode + +Warning: fopen(php://nonexistent): Failed to open stream: operation failed in %s on line %d Caught TypeError for error_store From dc7256642724b7f63eb06bb20ccb6e974c0b9223 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Mon, 29 Dec 2025 14:07:21 +0100 Subject: [PATCH 51/68] stream: add error begin and end to standard/streamsfuncs.c --- ext/standard/streamsfuncs.c | 104 ++++++++++++++++++++++++++++++------ 1 file changed, 87 insertions(+), 17 deletions(-) diff --git a/ext/standard/streamsfuncs.c b/ext/standard/streamsfuncs.c index e81e14c082175..89995889f9647 100644 --- a/ext/standard/streamsfuncs.c +++ b/ext/standard/streamsfuncs.c @@ -64,10 +64,13 @@ PHP_FUNCTION(stream_socket_pair) RETURN_FALSE; } + php_stream_error_operation_begin(); + s1 = php_stream_sock_open_from_socket(pair[0], 0); if (s1 == NULL) { close(pair[0]); close(pair[1]); + php_stream_error_operation_end(NULL); php_error_docref(NULL, E_WARNING, "Failed to open stream from socketpair"); RETURN_FALSE; } @@ -75,6 +78,7 @@ PHP_FUNCTION(stream_socket_pair) if (s2 == NULL) { php_stream_free(s1, PHP_STREAM_FREE_CLOSE); close(pair[1]); + php_stream_error_operation_end(NULL); php_error_docref(NULL, E_WARNING, "Failed to open stream from socketpair"); RETURN_FALSE; } @@ -88,6 +92,8 @@ PHP_FUNCTION(stream_socket_pair) add_next_index_resource(return_value, s1->res); add_next_index_resource(return_value, s2->res); + + php_stream_error_operation_end(NULL); } /* }}} */ #endif @@ -126,6 +132,7 @@ PHP_FUNCTION(stream_socket_client) RETURN_THROWS(); } + php_stream_error_operation_begin(); context = php_stream_context_from_zval(zcontext, flags & PHP_FILE_NO_DEFAULT_CONTEXT); if (flags & PHP_STREAM_CLIENT_PERSISTENT) { @@ -160,6 +167,7 @@ PHP_FUNCTION(stream_socket_client) (flags & PHP_STREAM_CLIENT_ASYNC_CONNECT ? STREAM_XPORT_CONNECT_ASYNC : 0), hashkey, tv_pointer, context, &errstr, &err); + php_stream_error_operation_end(context); if (stream == NULL) { /* host might contain binary characters */ @@ -217,6 +225,7 @@ PHP_FUNCTION(stream_socket_server) Z_PARAM_RESOURCE_OR_NULL(zcontext) ZEND_PARSE_PARAMETERS_END(); + php_stream_error_operation_begin(); context = php_stream_context_from_zval(zcontext, flags & PHP_FILE_NO_DEFAULT_CONTEXT); if (zerrno) { @@ -230,6 +239,8 @@ PHP_FUNCTION(stream_socket_server) STREAM_XPORT_SERVER | (int)flags, NULL, NULL, context, &errstr, &err); + php_stream_error_operation_end(context); + if (stream == NULL) { php_error_docref(NULL, E_WARNING, "Unable to connect to %s (%s)", host, errstr == NULL ? "Unknown error" : ZSTR_VAL(errstr)); } @@ -295,6 +306,8 @@ PHP_FUNCTION(stream_socket_accept) tv_pointer = &tv; } + php_stream_error_operation_begin(); + if (0 == php_stream_xport_accept(stream, &clistream, zpeername ? &peername : NULL, NULL, NULL, @@ -313,6 +326,8 @@ PHP_FUNCTION(stream_socket_accept) RETVAL_FALSE; } + php_stream_error_operation_end_for_stream(stream); + if (errstr) { zend_string_release_ex(errstr, 0); } @@ -331,10 +346,11 @@ PHP_FUNCTION(stream_socket_get_name) Z_PARAM_BOOL(want_peer) ZEND_PARSE_PARAMETERS_END(); - if (0 != php_stream_xport_get_name(stream, want_peer, - &name, - NULL, NULL - ) || !name) { + php_stream_error_operation_begin(); + int ret = php_stream_xport_get_name(stream, want_peer, &name, NULL, NULL); + php_stream_error_operation_end_for_stream(stream); + + if (0 != ret || !name) { RETURN_FALSE; } @@ -365,15 +381,18 @@ PHP_FUNCTION(stream_socket_sendto) Z_PARAM_STRING(target_addr, target_addr_len) ZEND_PARSE_PARAMETERS_END(); + php_stream_error_operation_begin(); if (target_addr_len) { /* parse the address */ if (FAILURE == php_network_parse_network_address_with_port(target_addr, target_addr_len, (struct sockaddr*)&sa, &sl)) { + php_stream_error_operation_end_for_stream(stream); php_error_docref(NULL, E_WARNING, "Failed to parse `%s' into a valid network address", target_addr); RETURN_FALSE; } } - RETURN_LONG(php_stream_xport_sendto(stream, data, datalen, (int)flags, target_addr_len ? &sa : NULL, sl)); + RETVAL_LONG(php_stream_xport_sendto(stream, data, datalen, (int)flags, target_addr_len ? &sa : NULL, sl)); + php_stream_error_operation_end_for_stream(stream); } /* }}} */ @@ -407,9 +426,10 @@ PHP_FUNCTION(stream_socket_recvfrom) read_buf = zend_string_alloc(to_read, 0); + php_stream_error_operation_begin(); recvd = php_stream_xport_recvfrom(stream, ZSTR_VAL(read_buf), to_read, (int)flags, NULL, NULL, - zremote ? &remote_addr : NULL - ); + zremote ? &remote_addr : NULL); + php_stream_error_operation_end_for_stream(stream); if (recvd >= 0) { if (zremote && remote_addr) { @@ -447,6 +467,8 @@ PHP_FUNCTION(stream_get_contents) RETURN_THROWS(); } + php_stream_error_operation_begin(); + if (desiredpos >= 0) { int seek_res = 0; zend_off_t position; @@ -461,6 +483,7 @@ PHP_FUNCTION(stream_get_contents) } if (seek_res != 0) { + php_stream_error_operation_end_for_stream(stream); php_error_docref(NULL, E_WARNING, "Failed to seek to position " ZEND_LONG_FMT " in the stream", desiredpos); RETURN_FALSE; @@ -468,10 +491,11 @@ PHP_FUNCTION(stream_get_contents) } if ((contents = php_stream_copy_to_mem(stream, maxlen, 0))) { - RETURN_STR(contents); + RETVAL_STR(contents); } else { - RETURN_EMPTY_STRING(); + RETVAL_EMPTY_STRING(); } + php_stream_error_operation_end_for_stream(stream); } /* }}} */ @@ -495,15 +519,20 @@ PHP_FUNCTION(stream_copy_to_stream) maxlen = PHP_STREAM_COPY_ALL; } + php_stream_error_operation_begin(); + if (pos > 0 && php_stream_seek(src, pos, SEEK_SET) < 0) { + php_stream_error_operation_end(NULL); php_error_docref(NULL, E_WARNING, "Failed to seek to position " ZEND_LONG_FMT " in the stream", pos); RETURN_FALSE; } if (php_stream_copy_to_stream_ex(src, dest, maxlen, &len) != SUCCESS) { - RETURN_FALSE; + RETVAL_FALSE; + } else { + RETVAL_LONG(len); } - RETURN_LONG(len); + php_stream_error_operation_end(NULL); } /* }}} */ @@ -518,11 +547,13 @@ PHP_FUNCTION(stream_get_meta_data) array_init(return_value); + php_stream_error_operation_begin(); if (!php_stream_populate_meta_data(stream, return_value)) { add_assoc_bool(return_value, "timed_out", 0); add_assoc_bool(return_value, "blocked", 1); add_assoc_bool(return_value, "eof", php_stream_eof(stream)); } + php_stream_error_operation_end_for_stream(stream); if (!Z_ISUNDEF(stream->wrapperdata)) { Z_ADDREF_P(&stream->wrapperdata); @@ -770,6 +801,8 @@ PHP_FUNCTION(stream_select) FD_ZERO(&wfds); FD_ZERO(&efds); + php_stream_error_operation_begin(); + if (r_array != NULL) { set_count = stream_array_to_fd_set(Z_ARR_P(r_array), &rfds, &max_fd); if (set_count > max_set_count) @@ -792,6 +825,7 @@ PHP_FUNCTION(stream_select) } if (!sets) { + php_stream_error_operation_end(NULL); zend_value_error("No stream arrays were passed"); RETURN_THROWS(); } @@ -802,6 +836,7 @@ PHP_FUNCTION(stream_select) if (secnull && !usecnull) { if (usec != 0) { + php_stream_error_operation_end(NULL); zend_argument_value_error(5, "must be null when argument #4 ($seconds) is null"); RETURN_THROWS(); } @@ -810,9 +845,11 @@ PHP_FUNCTION(stream_select) /* If seconds is not set to null, build the timeval, else we wait indefinitely */ if (!secnull) { if (sec < 0) { + php_stream_error_operation_end(NULL); zend_argument_value_error(4, "must be greater than or equal to 0"); RETURN_THROWS(); } else if (usec < 0) { + php_stream_error_operation_end(NULL); zend_argument_value_error(5, "must be greater than or equal to 0"); RETURN_THROWS(); } @@ -829,6 +866,7 @@ PHP_FUNCTION(stream_select) if (r_array != NULL) { retval = stream_array_emulate_read_fd_set(r_array); if (retval > 0) { + php_stream_error_operation_end(NULL); if (w_array != NULL) { zval_ptr_dtor(w_array); ZVAL_EMPTY_ARRAY(w_array); @@ -842,6 +880,7 @@ PHP_FUNCTION(stream_select) } retval = php_select(max_fd+1, &rfds, &wfds, &efds, tv_p); + php_stream_error_operation_end(NULL); if (retval == -1) { php_error_docref(NULL, E_WARNING, "Unable to select [%d]: %s (max_fd=" PHP_SOCKET_FMT ")", @@ -1362,11 +1401,13 @@ PHP_FUNCTION(stream_get_line) max_length = PHP_SOCK_CHUNK_SIZE; } + php_stream_error_operation_begin(); if ((buf = php_stream_get_record(stream, max_length, str, str_len))) { - RETURN_STR(buf); + RETVAL_STR(buf); } else { - RETURN_FALSE; + RETVAL_FALSE; } + php_stream_error_operation_end_for_stream(stream); } /* }}} */ @@ -1382,7 +1423,9 @@ PHP_FUNCTION(stream_set_blocking) Z_PARAM_BOOL(block) ZEND_PARSE_PARAMETERS_END(); - RETURN_BOOL(-1 != php_stream_set_option(stream, PHP_STREAM_OPTION_BLOCKING, block, NULL)); + php_stream_error_operation_begin(); + RETVAL_BOOL(-1 != php_stream_set_option(stream, PHP_STREAM_OPTION_BLOCKING, block, NULL)); + php_stream_error_operation_end_for_stream(stream); } /* }}} */ @@ -1423,7 +1466,9 @@ PHP_FUNCTION(stream_set_timeout) } #endif - RETURN_BOOL(PHP_STREAM_OPTION_RETURN_OK == php_stream_set_option(stream, PHP_STREAM_OPTION_READ_TIMEOUT, 0, &t)); + php_stream_error_operation_begin(); + RETVAL_BOOL(PHP_STREAM_OPTION_RETURN_OK == php_stream_set_option(stream, PHP_STREAM_OPTION_READ_TIMEOUT, 0, &t)); + php_stream_error_operation_end_for_stream(stream); } #endif /* HAVE_SYS_TIME_H || defined(PHP_WIN32) */ /* }}} */ @@ -1443,12 +1488,14 @@ PHP_FUNCTION(stream_set_write_buffer) buff = arg2; + php_stream_error_operation_begin(); /* if buff is 0 then set to non-buffered */ if (buff == 0) { ret = php_stream_set_option(stream, PHP_STREAM_OPTION_WRITE_BUFFER, PHP_STREAM_BUFFER_NONE, NULL); } else { ret = php_stream_set_option(stream, PHP_STREAM_OPTION_WRITE_BUFFER, PHP_STREAM_BUFFER_FULL, &buff); } + php_stream_error_operation_end_for_stream(stream); RETURN_LONG(ret == 0 ? 0 : EOF); } @@ -1479,7 +1526,9 @@ PHP_FUNCTION(stream_set_chunk_size) RETURN_THROWS(); } + php_stream_error_operation_begin(); ret = php_stream_set_option(stream, PHP_STREAM_OPTION_SET_CHUNK_SIZE, (int)csize, NULL); + php_stream_error_operation_end_for_stream(stream); RETURN_LONG(ret > 0 ? (zend_long)ret : (zend_long)EOF); } @@ -1500,12 +1549,14 @@ PHP_FUNCTION(stream_set_read_buffer) buff = arg2; + php_stream_error_operation_begin(); /* if buff is 0 then set to non-buffered */ if (buff == 0) { ret = php_stream_set_option(stream, PHP_STREAM_OPTION_READ_BUFFER, PHP_STREAM_BUFFER_NONE, NULL); } else { ret = php_stream_set_option(stream, PHP_STREAM_OPTION_READ_BUFFER, PHP_STREAM_BUFFER_FULL, &buff); } + php_stream_error_operation_end_for_stream(stream); RETURN_LONG(ret == 0 ? 0 : EOF); } @@ -1527,11 +1578,14 @@ PHP_FUNCTION(stream_socket_enable_crypto) PHP_Z_PARAM_STREAM_OR_NULL(sessstream) ZEND_PARSE_PARAMETERS_END(); + php_stream_error_operation_begin(); + if (enable) { if (cryptokindnull) { zval *val; if (!GET_CTX_OPT(stream, "ssl", "crypto_method", val)) { + php_stream_error_operation_end_for_stream(stream); zend_argument_value_error(3, "must be specified when enabling encryption"); RETURN_THROWS(); } @@ -1540,11 +1594,13 @@ PHP_FUNCTION(stream_socket_enable_crypto) } if (php_stream_xport_crypto_setup(stream, cryptokind, sessstream) < 0) { + php_stream_error_operation_end_for_stream(stream); RETURN_FALSE; } } ret = php_stream_xport_crypto_enable(stream, enable); + php_stream_error_operation_end_for_stream(stream); switch (ret) { case -1: RETURN_FALSE; @@ -1596,7 +1652,9 @@ PHP_FUNCTION(stream_is_local) RETURN_THROWS(); } + php_stream_error_operation_begin(); wrapper = php_stream_locate_url_wrapper(Z_STRVAL_P(zstream), NULL, 0); + php_stream_error_operation_end(NULL); } RETURN_BOOL(wrapper && wrapper->is_url == 0); @@ -1612,7 +1670,9 @@ PHP_FUNCTION(stream_supports_lock) PHP_Z_PARAM_STREAM(stream) ZEND_PARSE_PARAMETERS_END(); - RETURN_BOOL(php_stream_supports_lock(stream)); + php_stream_error_operation_begin(); + RETVAL_BOOL(php_stream_supports_lock(stream)); + php_stream_error_operation_end_for_stream(stream); } /* {{{ Check if a stream is a TTY. */ @@ -1625,6 +1685,8 @@ PHP_FUNCTION(stream_isatty) PHP_Z_PARAM_STREAM(stream) ZEND_PARSE_PARAMETERS_END(); + php_stream_error_operation_begin(); + /* get the fd. * NB: Most other code will NOT use the PHP_STREAM_CAST_INTERNAL flag when casting. * It is only used here so that the buffered data warning is not displayed. @@ -1634,8 +1696,10 @@ PHP_FUNCTION(stream_isatty) } else if (php_stream_can_cast(stream, PHP_STREAM_AS_FD | PHP_STREAM_CAST_INTERNAL) == SUCCESS) { php_stream_cast(stream, PHP_STREAM_AS_FD | PHP_STREAM_CAST_INTERNAL, (void*)&fileno, 0); } else { + php_stream_error_operation_end_for_stream(stream); RETURN_FALSE; } + php_stream_error_operation_end_for_stream(stream); #ifdef PHP_WIN32 /* Check if the Windows standard handle is redirected to file */ @@ -1665,6 +1729,8 @@ PHP_FUNCTION(sapi_windows_vt100_support) Z_PARAM_BOOL_OR_NULL(enable, enable_is_null) ZEND_PARSE_PARAMETERS_END(); + php_stream_error_operation_begin(); + /* get the fd. * NB: Most other code will NOT use the PHP_STREAM_CAST_INTERNAL flag when casting. * It is only used here so that the buffered data warning is not displayed. @@ -1674,6 +1740,7 @@ PHP_FUNCTION(sapi_windows_vt100_support) } else if (php_stream_can_cast(stream, PHP_STREAM_AS_FD | PHP_STREAM_CAST_INTERNAL) == SUCCESS) { php_stream_cast(stream, PHP_STREAM_AS_FD | PHP_STREAM_CAST_INTERNAL, (void*)&fileno, 0); } else { + php_stream_error_operation_end_for_stream(stream); if (!enable_is_null) { php_error_docref( NULL, @@ -1683,6 +1750,7 @@ PHP_FUNCTION(sapi_windows_vt100_support) } RETURN_FALSE; } + php_stream_error_operation_end_for_stream(stream); /* Check if the file descriptor is a console */ if (!php_win32_console_fileno_is_console(fileno)) { @@ -1722,7 +1790,9 @@ PHP_FUNCTION(stream_socket_shutdown) RETURN_THROWS(); } - RETURN_BOOL(php_stream_xport_shutdown(stream, (stream_shutdown_t)how) == 0); + php_stream_error_operation_begin(); + RETVAL_BOOL(php_stream_xport_shutdown(stream, (stream_shutdown_t)how) == 0); + php_stream_error_operation_end_for_stream(stream); } /* }}} */ #endif From ccd3f5152506ade54bd82568e601f0f909729808 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Mon, 29 Dec 2025 14:13:59 +0100 Subject: [PATCH 52/68] stream: use default context in errors if no context set --- main/streams/stream_errors.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/main/streams/stream_errors.c b/main/streams/stream_errors.c index 94578ab6341e3..f9b2407242af3 100644 --- a/main/streams/stream_errors.c +++ b/main/streams/stream_errors.c @@ -413,6 +413,9 @@ PHPAPI void php_stream_error_operation_end(php_stream_context *context) /* Process errors if we have any */ if (op->error_count > 0) { + if (context == NULL) { + context = FG(default_context); + } /* Get error handling settings */ int error_mode = php_stream_get_error_mode(context); int store_mode = php_stream_get_error_store_mode(context, error_mode); From a404f633c853321ea2a7e083b1f30c03fef76698 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Mon, 29 Dec 2025 14:15:43 +0100 Subject: [PATCH 53/68] stream: remove php_stream_error_operation_free --- main/streams/stream_errors.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/main/streams/stream_errors.c b/main/streams/stream_errors.c index f9b2407242af3..c800b25c117d9 100644 --- a/main/streams/stream_errors.c +++ b/main/streams/stream_errors.c @@ -177,12 +177,6 @@ static void php_stream_error_entry_free(php_stream_error_entry *entry) } } -static void php_stream_error_operation_free(php_stream_error_operation *op) -{ - php_stream_error_entry_free(op->first_error); - efree(op); -} - PHPAPI void php_stream_error_state_cleanup(void) { php_stream_error_state *state = &FG(stream_error_state); From 65a6c6848b091f57df420ccb9b0edec560c200c3 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Mon, 29 Dec 2025 17:54:57 +0100 Subject: [PATCH 54/68] stream: fix stored errors copying --- main/streams/stream_errors.c | 35 ++++++++++++++--------------------- 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/main/streams/stream_errors.c b/main/streams/stream_errors.c index c800b25c117d9..485a308fd17ef 100644 --- a/main/streams/stream_errors.c +++ b/main/streams/stream_errors.c @@ -410,6 +410,7 @@ PHPAPI void php_stream_error_operation_end(php_stream_context *context) if (context == NULL) { context = FG(default_context); } + /* Get error handling settings */ int error_mode = php_stream_get_error_mode(context); int store_mode = php_stream_get_error_store_mode(context, error_mode); @@ -423,12 +424,14 @@ PHPAPI void php_stream_error_operation_end(php_stream_context *context) if (store_mode == PHP_STREAM_ERROR_STORE_NONE) { /* Free all errors */ php_stream_error_entry_free(op->first_error); + op->first_error = NULL; } else { /* Filter and store */ php_stream_error_entry *entry = op->first_error; php_stream_error_entry *prev = NULL; php_stream_error_entry *to_store_first = NULL; php_stream_error_entry *to_store_last = NULL; + php_stream_error_entry *remaining_first = NULL; while (entry) { php_stream_error_entry *next = entry->next; @@ -444,12 +447,6 @@ PHPAPI void php_stream_error_operation_end(php_stream_context *context) if (should_store) { /* Move to storage chain */ - if (prev) { - prev->next = next; - } else { - op->first_error = next; - } - entry->next = NULL; if (to_store_last) { to_store_last->next = entry; @@ -458,24 +455,16 @@ PHPAPI void php_stream_error_operation_end(php_stream_context *context) } to_store_last = entry; } else { - /* Free this error */ + /* Keep in remaining chain (to be freed) */ + entry->next = NULL; if (prev) { - prev->next = next; + prev->next = entry; } else { - op->first_error = next; + remaining_first = entry; } - - zend_string_release(entry->message); - efree(entry->wrapper_name); - efree(entry->param); - efree(entry->docref); - efree(entry); - - entry = next; - continue; + prev = entry; } - prev = entry; entry = next; } @@ -489,8 +478,12 @@ PHPAPI void php_stream_error_operation_end(php_stream_context *context) state->stored_count++; } - /* Free any remaining errors not moved to storage */ - php_stream_error_entry_free(op->first_error); + /* Free remaining errors that were not stored */ + if (remaining_first) { + php_stream_error_entry_free(remaining_first); + } + + op->first_error = NULL; } } From 540d000da3cc8cb58b5ee73d5eadc0232d8172b3 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Mon, 29 Dec 2025 17:55:18 +0100 Subject: [PATCH 55/68] stream: fix mix modes storage error test --- .../stream_errors_mix_modes_storage.phpt | 56 ++++++++++--------- 1 file changed, 31 insertions(+), 25 deletions(-) diff --git a/ext/standard/tests/streams/stream_errors_mix_modes_storage.phpt b/ext/standard/tests/streams/stream_errors_mix_modes_storage.phpt index 80dd85a4a386b..048949d5353b5 100644 --- a/ext/standard/tests/streams/stream_errors_mix_modes_storage.phpt +++ b/ext/standard/tests/streams/stream_errors_mix_modes_storage.phpt @@ -28,7 +28,8 @@ class TestStream { stream_wrapper_register('test', 'TestStream'); function stream_test_errors($title, $context) { - $stream = fopen('test://foo', 'r', false, $context); + stream_context_set_default($context); + $stream = fopen('test://foo', 'r', false); try { echo $title . "\n"; $readin = fopen('php://stdin', 'r'); @@ -55,7 +56,7 @@ function stream_test_errors($title, $context) { $current = $error; $idx = 0; while ($current) { - echo " [$idx] " . $current->code->name . ": " . substr($current->message, 0, 50) . "...\n"; + echo " [$idx] " . $current->code->name . ": " . $current->message . "\n"; $current = $current->next; $idx++; } @@ -65,53 +66,52 @@ function stream_test_errors($title, $context) { echo "\n"; } -stream_test_errors('ALL', stream_context_create([ +stream_test_errors('ALL', [ 'stream' => [ 'error_mode' => StreamErrorMode::Silent, 'error_store' => StreamErrorStore::All, ] -])); +]); -stream_test_errors('NON TERMINAL', stream_context_create([ +stream_test_errors('NON TERMINAL', [ 'stream' => [ 'error_mode' => StreamErrorMode::Silent, 'error_store' => StreamErrorStore::NonTerminal, ] -])); +]); -stream_test_errors('TERMINAL', stream_context_create([ +stream_test_errors('TERMINAL', [ 'stream' => [ 'error_mode' => StreamErrorMode::Silent, 'error_store' => StreamErrorStore::Terminal, ] -])); +]); -stream_test_errors('AUTO EXCEPTION', stream_context_create([ +stream_test_errors('AUTO EXCEPTION', [ 'stream' => [ 'error_mode' => StreamErrorMode::Exception, 'error_store' => StreamErrorStore::Auto, ] -])); +]); -stream_test_errors('AUTO ERROR', stream_context_create([ +stream_test_errors('AUTO ERROR', [ 'stream' => [ 'error_mode' => StreamErrorMode::Error, 'error_store' => StreamErrorStore::Auto, ] -])); +]); ?> --EXPECTF-- ALL Error details: -- Message: TestStream::stream_read - read 10 bytes more data than requested (8202 read, 8192 max) - excess data will be lost -- Code: UserspaceInvalidReturn (161) +- Message: TestStream::stream_cast is not implemented! +- Code: NotImplemented (70) - Wrapper: user-space -- Terminating: no -- Count: 3 - [0] UserspaceInvalidReturn: TestStream::stream_read - read 10 bytes more data ... - [1] NotImplemented: TestStream::stream_cast is not implemented!... - [2] CastNotSupported: Cannot represent a stream of type user-space as... +- Terminating: yes +- Count: 2 + [0] NotImplemented: TestStream::stream_cast is not implemented! + [1] CastNotSupported: Cannot represent a stream of type user-space as a select()able descriptor NON TERMINAL Error details: @@ -120,7 +120,7 @@ Error details: - Wrapper: user-space - Terminating: no - Count: 1 - [0] UserspaceInvalidReturn: TestStream::stream_read - read 10 bytes more data ... + [0] UserspaceInvalidReturn: TestStream::stream_read - read 10 bytes more data than requested (8202 read, 8192 max) - excess data will be lost TERMINAL Error details: @@ -129,18 +129,18 @@ Error details: - Wrapper: user-space - Terminating: yes - Count: 2 - [0] NotImplemented: TestStream::stream_cast is not implemented!... - [1] CastNotSupported: Cannot represent a stream of type user-space as... + [0] NotImplemented: TestStream::stream_cast is not implemented! + [1] CastNotSupported: Cannot represent a stream of type user-space as a select()able descriptor AUTO EXCEPTION -EXCEPTION: Cannot represent a stream of type user-space as a select()able descriptor +EXCEPTION: TestStream::stream_cast is not implemented! Error details: - Message: TestStream::stream_read - read 10 bytes more data than requested (8202 read, 8192 max) - excess data will be lost - Code: UserspaceInvalidReturn (161) - Wrapper: user-space - Terminating: no - Count: 1 - [0] UserspaceInvalidReturn: TestStream::stream_read - read 10 bytes more data ... + [0] UserspaceInvalidReturn: TestStream::stream_read - read 10 bytes more data than requested (8202 read, 8192 max) - excess data will be lost AUTO ERROR @@ -149,4 +149,10 @@ Warning: fread(): TestStream::stream_read - read 10 bytes more data than request Warning: stream_select(): TestStream::stream_cast is not implemented! in %s on line %d Warning: stream_select(): Cannot represent a stream of type user-space as a select()able descriptor in %s on line %d -No errors stored +Error details: +- Message: TestStream::stream_read - read 10 bytes more data than requested (8202 read, 8192 max) - excess data will be lost +- Code: UserspaceInvalidReturn (161) +- Wrapper: user-space +- Terminating: no +- Count: 1 + [0] UserspaceInvalidReturn: TestStream::stream_read - read 10 bytes more data than requested (8202 read, 8192 max) - excess data will be lost From 2739122d81927f763d0ef0bec3b27d80f230e9e9 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Mon, 29 Dec 2025 17:56:14 +0100 Subject: [PATCH 56/68] stream: remove chaining tests (already tested by mixed store) --- .../tests/streams/stream_errors_chaining.phpt | 41 ------------------- 1 file changed, 41 deletions(-) delete mode 100644 ext/standard/tests/streams/stream_errors_chaining.phpt diff --git a/ext/standard/tests/streams/stream_errors_chaining.phpt b/ext/standard/tests/streams/stream_errors_chaining.phpt deleted file mode 100644 index 859e468d3f5ee..0000000000000 --- a/ext/standard/tests/streams/stream_errors_chaining.phpt +++ /dev/null @@ -1,41 +0,0 @@ ---TEST-- -Stream errors - error chaining ---FILE-- - [ - 'error_mode' => StreamErrorMode::Silent, - 'error_store' => StreamErrorStore::All, - ] -]); - -$stream = fopen('test://foo', 'r', false, $context); - -$error = stream_get_last_error(); -if ($error) { - echo "Error count: " . $error->count() . "\n"; - echo "First error: " . $error->message . "\n"; - - // Check if it has next error - if ($error->next) { - echo "Has chained error: yes\n"; - } -} - -?> ---EXPECTF-- -Error count: %d -First error: %s -%a From b960b772594ba926cf19134097c35310d2fd166b Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Mon, 29 Dec 2025 17:57:26 +0100 Subject: [PATCH 57/68] stream: update reflection class names test --- .../tests/ReflectionExtension_getClassNames_basic.phpt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ext/reflection/tests/ReflectionExtension_getClassNames_basic.phpt b/ext/reflection/tests/ReflectionExtension_getClassNames_basic.phpt index dc72254abc076..4e985e674f229 100644 --- a/ext/reflection/tests/ReflectionExtension_getClassNames_basic.phpt +++ b/ext/reflection/tests/ReflectionExtension_getClassNames_basic.phpt @@ -16,6 +16,10 @@ AssertionError Directory RoundingMode StreamBucket +StreamError +StreamErrorCode +StreamErrorMode +StreamErrorStore StreamException __PHP_Incomplete_Class php_user_filter From 397473f862fbaa52d0061e137e19084e564a6712 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Mon, 29 Dec 2025 18:38:16 +0100 Subject: [PATCH 58/68] stream: rename terminal errors to terminating --- .../streams/stream_errors_mix_modes_storage.phpt | 12 ++++++------ main/streams/stream_errors.c | 4 ++-- main/streams/stream_errors.stub.php | 4 ++-- main/streams/stream_errors_arginfo.h | 6 +++--- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/ext/standard/tests/streams/stream_errors_mix_modes_storage.phpt b/ext/standard/tests/streams/stream_errors_mix_modes_storage.phpt index 048949d5353b5..5e61108b63bda 100644 --- a/ext/standard/tests/streams/stream_errors_mix_modes_storage.phpt +++ b/ext/standard/tests/streams/stream_errors_mix_modes_storage.phpt @@ -73,17 +73,17 @@ stream_test_errors('ALL', [ ] ]); -stream_test_errors('NON TERMINAL', [ +stream_test_errors('NON TERMINATING', [ 'stream' => [ 'error_mode' => StreamErrorMode::Silent, - 'error_store' => StreamErrorStore::NonTerminal, + 'error_store' => StreamErrorStore::NonTerminating, ] ]); -stream_test_errors('TERMINAL', [ +stream_test_errors('TERMINATING', [ 'stream' => [ 'error_mode' => StreamErrorMode::Silent, - 'error_store' => StreamErrorStore::Terminal, + 'error_store' => StreamErrorStore::Terminating, ] ]); @@ -113,7 +113,7 @@ Error details: [0] NotImplemented: TestStream::stream_cast is not implemented! [1] CastNotSupported: Cannot represent a stream of type user-space as a select()able descriptor -NON TERMINAL +NON TERMINATING Error details: - Message: TestStream::stream_read - read 10 bytes more data than requested (8202 read, 8192 max) - excess data will be lost - Code: UserspaceInvalidReturn (161) @@ -122,7 +122,7 @@ Error details: - Count: 1 [0] UserspaceInvalidReturn: TestStream::stream_read - read 10 bytes more data than requested (8202 read, 8192 max) - excess data will be lost -TERMINAL +TERMINATING Error details: - Message: TestStream::stream_cast is not implemented! - Code: NotImplemented (70) diff --git a/main/streams/stream_errors.c b/main/streams/stream_errors.c index 485a308fd17ef..555f6f38c12ec 100644 --- a/main/streams/stream_errors.c +++ b/main/streams/stream_errors.c @@ -112,9 +112,9 @@ static int php_stream_get_error_store_mode(php_stream_context *context, int erro return php_stream_auto_decide_error_store_mode(error_mode); } else if (zend_string_equals_literal(case_name, "None")) { return PHP_STREAM_ERROR_STORE_NONE; - } else if (zend_string_equals_literal(case_name, "NonTerminal")) { + } else if (zend_string_equals_literal(case_name, "NonTerminating")) { return PHP_STREAM_ERROR_STORE_NON_TERM; - } else if (zend_string_equals_literal(case_name, "Terminal")) { + } else if (zend_string_equals_literal(case_name, "Terminating")) { return PHP_STREAM_ERROR_STORE_TERMINAL; } else if (zend_string_equals_literal(case_name, "All")) { return PHP_STREAM_ERROR_STORE_ALL; diff --git a/main/streams/stream_errors.stub.php b/main/streams/stream_errors.stub.php index 83e44ca75c9bf..8b6b549a68eb7 100644 --- a/main/streams/stream_errors.stub.php +++ b/main/streams/stream_errors.stub.php @@ -38,8 +38,8 @@ enum StreamErrorStore { case Auto; case None; - case NonTerminal; - case Terminal; + case NonTerminating; + case Terminating; case All; } diff --git a/main/streams/stream_errors_arginfo.h b/main/streams/stream_errors_arginfo.h index 1675213fd99ae..7fded66ec89d5 100644 --- a/main/streams/stream_errors_arginfo.h +++ b/main/streams/stream_errors_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: c9a7e6c0b34de0c6ee76c2a9d80c50deafc8079a */ + * Stub hash: 24a4229f4272983a6fb996ce136ea904183e14e0 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_StreamErrorCode_isIoError, 0, 0, _IS_BOOL, 0) ZEND_END_ARG_INFO() @@ -99,9 +99,9 @@ static zend_class_entry *register_class_StreamErrorStore(void) zend_enum_add_case_cstr(class_entry, "None", NULL); - zend_enum_add_case_cstr(class_entry, "NonTerminal", NULL); + zend_enum_add_case_cstr(class_entry, "NonTerminating", NULL); - zend_enum_add_case_cstr(class_entry, "Terminal", NULL); + zend_enum_add_case_cstr(class_entry, "Terminating", NULL); zend_enum_add_case_cstr(class_entry, "All", NULL); From 1cf9820283a93c2d0ffa57b16586315d752f9856 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Mon, 29 Dec 2025 19:18:38 +0100 Subject: [PATCH 59/68] stream: fix segfault with incompletely zeroed entry in dtor --- main/streams/stream_errors.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/main/streams/stream_errors.c b/main/streams/stream_errors.c index 555f6f38c12ec..4e2b68efd82fb 100644 --- a/main/streams/stream_errors.c +++ b/main/streams/stream_errors.c @@ -681,14 +681,13 @@ static void php_stream_wrapper_log_store_error(zend_string *message, int code, { char *param_copy = param ? estrdup(param) : NULL; - php_stream_error_entry *entry = emalloc(sizeof(php_stream_error_entry)); + php_stream_error_entry *entry = ecalloc(1, sizeof(php_stream_error_entry)); entry->message = message; entry->code = code; entry->wrapper_name = wrapper_name ? estrdup(wrapper_name) : NULL; entry->param = param_copy; entry->severity = severity; entry->terminating = terminating; - entry->next = NULL; if (!FG(wrapper_logged_errors)) { ALLOC_HASHTABLE(FG(wrapper_logged_errors)); From 1d5f2456a90ef34dc025f2af9e5b5a6265fbe6d3 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Mon, 29 Dec 2025 19:22:32 +0100 Subject: [PATCH 60/68] stream: re-order some errors and fix test --- ext/standard/file.c | 20 ++++++++++---------- ext/standard/tests/streams/gh14506.phpt | 4 ++-- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/ext/standard/file.c b/ext/standard/file.c index 11ac70a5fcd55..b5809f48c10ab 100644 --- a/ext/standard/file.c +++ b/ext/standard/file.c @@ -427,9 +427,9 @@ PHP_FUNCTION(file_get_contents) } if (offset != 0 && php_stream_seek(stream, offset, ((offset > 0) ? SEEK_SET : SEEK_END)) < 0) { - php_error_docref(NULL, E_WARNING, "Failed to seek to position " ZEND_LONG_FMT " in the stream", offset); php_stream_close(stream); php_stream_error_operation_end(context); + php_error_docref(NULL, E_WARNING, "Failed to seek to position " ZEND_LONG_FMT " in the stream", offset); RETURN_FALSE; } @@ -495,8 +495,8 @@ PHP_FUNCTION(file_put_contents) if ((flags & LOCK_EX) && (!php_stream_supports_lock(stream) || php_stream_lock(stream, LOCK_EX))) { php_stream_close(stream); - php_error_docref(NULL, E_WARNING, "Exclusive locks are not supported for this stream"); php_stream_error_operation_end(context); + php_error_docref(NULL, E_WARNING, "Exclusive locks are not supported for this stream"); RETURN_FALSE; } @@ -1264,20 +1264,20 @@ PHP_FUNCTION(rename) wrapper = php_stream_locate_url_wrapper(old_name, NULL, 0); if (!wrapper || !wrapper->wops) { - php_error_docref(NULL, E_WARNING, "Unable to locate stream wrapper"); php_stream_error_operation_end(context); + php_error_docref(NULL, E_WARNING, "Unable to locate stream wrapper"); RETURN_FALSE; } if (!wrapper->wops->rename) { - php_error_docref(NULL, E_WARNING, "%s wrapper does not support renaming", wrapper->wops->label ? wrapper->wops->label : "Source"); php_stream_error_operation_end(context); + php_error_docref(NULL, E_WARNING, "%s wrapper does not support renaming", wrapper->wops->label ? wrapper->wops->label : "Source"); RETURN_FALSE; } if (wrapper != php_stream_locate_url_wrapper(new_name, NULL, 0)) { - php_error_docref(NULL, E_WARNING, "Cannot rename a file across wrapper types"); php_stream_error_operation_end(context); + php_error_docref(NULL, E_WARNING, "Cannot rename a file across wrapper types"); RETURN_FALSE; } @@ -1307,14 +1307,14 @@ PHP_FUNCTION(unlink) wrapper = php_stream_locate_url_wrapper(filename, NULL, 0); if (!wrapper || !wrapper->wops) { - php_error_docref(NULL, E_WARNING, "Unable to locate stream wrapper"); php_stream_error_operation_end(context); + php_error_docref(NULL, E_WARNING, "Unable to locate stream wrapper"); RETURN_FALSE; } if (!wrapper->wops->unlink) { - php_error_docref(NULL, E_WARNING, "%s does not allow unlinking", wrapper->wops->label ? wrapper->wops->label : "Wrapper"); php_stream_error_operation_end(context); + php_error_docref(NULL, E_WARNING, "%s does not allow unlinking", wrapper->wops->label ? wrapper->wops->label : "Wrapper"); RETURN_FALSE; } RETVAL_BOOL(wrapper->wops->unlink(wrapper, filename, REPORT_ERRORS, context)); @@ -1332,8 +1332,8 @@ PHP_FUNCTION(fsync) php_stream_error_operation_begin(); if (!php_stream_sync_supported(stream)) { - php_error_docref(NULL, E_WARNING, "Can't fsync this stream!"); php_stream_error_operation_end_for_stream(stream); + php_error_docref(NULL, E_WARNING, "Can't fsync this stream!"); RETURN_FALSE; } @@ -1351,8 +1351,8 @@ PHP_FUNCTION(fdatasync) php_stream_error_operation_begin(); if (!php_stream_sync_supported(stream)) { - php_error_docref(NULL, E_WARNING, "Can't fsync this stream!"); php_stream_error_operation_end_for_stream(stream); + php_error_docref(NULL, E_WARNING, "Can't fsync this stream!"); RETURN_FALSE; } @@ -1379,8 +1379,8 @@ PHP_FUNCTION(ftruncate) php_stream_error_operation_begin(); if (!php_stream_truncate_supported(stream)) { - php_error_docref(NULL, E_WARNING, "Can't truncate this stream!"); php_stream_error_operation_end_for_stream(stream); + php_error_docref(NULL, E_WARNING, "Can't truncate this stream!"); RETURN_FALSE; } diff --git a/ext/standard/tests/streams/gh14506.phpt b/ext/standard/tests/streams/gh14506.phpt index f83eba4f1ff30..3d82350221d55 100644 --- a/ext/standard/tests/streams/gh14506.phpt +++ b/ext/standard/tests/streams/gh14506.phpt @@ -86,10 +86,10 @@ Warning: fclose(): cannot close the provided stream, as it must not be manually Warning: fclose(): cannot close the provided stream, as it must not be manually closed in %s on line %d -Warning: stream_select(): Cannot represent a stream of type user-space as a select()able descriptor in %s on line %d - Warning: fclose(): cannot close the provided stream, as it must not be manually closed in %s on line %d +Warning: stream_select(): Cannot represent a stream of type user-space as a select()able descriptor in %s on line %d + Warning: stream_select(): Cannot represent a stream of type user-space as a select()able descriptor in %s on line %d No stream arrays were passed fclose(): Argument #1 ($stream) must be an open stream resource From d3c613c59b890906c3cfc8f0418cf070f3d65881 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Mon, 29 Dec 2025 20:08:36 +0100 Subject: [PATCH 61/68] stream: update optimizer info for stream_get_last_error --- Zend/Optimizer/zend_func_infos.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Zend/Optimizer/zend_func_infos.h b/Zend/Optimizer/zend_func_infos.h index 16d254b3a38fd..86d7f478fe111 100644 --- a/Zend/Optimizer/zend_func_infos.h +++ b/Zend/Optimizer/zend_func_infos.h @@ -596,7 +596,7 @@ static const func_info_t func_infos[] = { F1("stream_get_line", MAY_BE_STRING|MAY_BE_FALSE), F1("stream_resolve_include_path", MAY_BE_STRING|MAY_BE_FALSE), F1("stream_get_wrappers", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_OF_STRING), - FN("stream_get_errors", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_OF_ARRAY), + F1("stream_get_last_error", MAY_BE_OBJECT|MAY_BE_NULL), F1("stream_get_transports", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_OF_STRING), #if defined(HAVE_GETTIMEOFDAY) F1("uniqid", MAY_BE_STRING), From ba088224e976b9780b73ed2932739ac7825dc048 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Fri, 27 Feb 2026 21:56:31 +0100 Subject: [PATCH 62/68] stream: use StreamError class constants for codes --- ...flectionExtension_getClassNames_basic.phpt | 1 - .../stream_errors_error_code_helpers.phpt | 10 +- ...stream_errors_exception_mode_terminal.phpt | 2 - .../stream_errors_mix_modes_storage.phpt | 28 +- .../streams/stream_errors_multi_store.phpt | 4 +- .../stream_errors_silent_with_handler.phpt | 4 +- .../stream_errors_silent_with_storage.phpt | 4 +- main/streams/php_stream_errors.h | 186 +++--- main/streams/stream_errors.c | 214 +++---- main/streams/stream_errors.stub.php | 223 +++++++- main/streams/stream_errors_arginfo.h | 536 ++++++++++++++++-- 11 files changed, 887 insertions(+), 325 deletions(-) diff --git a/ext/reflection/tests/ReflectionExtension_getClassNames_basic.phpt b/ext/reflection/tests/ReflectionExtension_getClassNames_basic.phpt index 4e985e674f229..34a951b45034d 100644 --- a/ext/reflection/tests/ReflectionExtension_getClassNames_basic.phpt +++ b/ext/reflection/tests/ReflectionExtension_getClassNames_basic.phpt @@ -17,7 +17,6 @@ Directory RoundingMode StreamBucket StreamError -StreamErrorCode StreamErrorMode StreamErrorStore StreamException diff --git a/ext/standard/tests/streams/stream_errors_error_code_helpers.phpt b/ext/standard/tests/streams/stream_errors_error_code_helpers.phpt index dc452e846fb4b..3a3f939da2998 100644 --- a/ext/standard/tests/streams/stream_errors_error_code_helpers.phpt +++ b/ext/standard/tests/streams/stream_errors_error_code_helpers.phpt @@ -1,5 +1,5 @@ --TEST-- -Stream errors - StreamErrorCode helper methods +Stream errors - StreamError helper methods --FILE-- code->isIoError() ? 'yes' : 'no') . "\n"; - echo "Is filesystem error: " . ($error->code->isFileSystemError() ? 'yes' : 'no') . "\n"; - echo "Is network error: " . ($error->code->isNetworkError() ? 'yes' : 'no') . "\n"; - echo "Is wrapper error: " . ($error->code->isWrapperError() ? 'yes' : 'no') . "\n"; + echo "Is I/O error: " . ($error->isIoError() ? 'yes' : 'no') . "\n"; + echo "Is filesystem error: " . ($error->isFileSystemError() ? 'yes' : 'no') . "\n"; + echo "Is network error: " . ($error->isNetworkError() ? 'yes' : 'no') . "\n"; + echo "Is wrapper error: " . ($error->isWrapperError() ? 'yes' : 'no') . "\n"; } ?> diff --git a/ext/standard/tests/streams/stream_errors_exception_mode_terminal.phpt b/ext/standard/tests/streams/stream_errors_exception_mode_terminal.phpt index d66e6d654f1df..fc3133b65a77b 100644 --- a/ext/standard/tests/streams/stream_errors_exception_mode_terminal.phpt +++ b/ext/standard/tests/streams/stream_errors_exception_mode_terminal.phpt @@ -18,7 +18,6 @@ try { $error = $e->getError(); if ($error) { echo "Wrapper: " . $error->wrapperName . "\n"; - echo "Error code name: " . $error->code->name . "\n"; } } @@ -27,4 +26,3 @@ try { Caught: Failed to open stream: operation failed Code: 36 Wrapper: PHP -Error code name: OpenFailed diff --git a/ext/standard/tests/streams/stream_errors_mix_modes_storage.phpt b/ext/standard/tests/streams/stream_errors_mix_modes_storage.phpt index 5e61108b63bda..1dd1972be2c7b 100644 --- a/ext/standard/tests/streams/stream_errors_mix_modes_storage.phpt +++ b/ext/standard/tests/streams/stream_errors_mix_modes_storage.phpt @@ -47,7 +47,7 @@ function stream_test_errors($title, $context) { if ($error) { echo "Error details:\n"; echo "- Message: " . $error->message . "\n"; - echo "- Code: " . $error->code->name . " (" . $error->code->value . ")\n"; + echo "- Code: $error->code\n"; echo "- Wrapper: " . $error->wrapperName . "\n"; echo "- Terminating: " . ($error->terminating ? 'yes' : 'no') . "\n"; echo "- Count: " . $error->count() . "\n"; @@ -56,7 +56,7 @@ function stream_test_errors($title, $context) { $current = $error; $idx = 0; while ($current) { - echo " [$idx] " . $current->code->name . ": " . $current->message . "\n"; + echo " [$idx] " . $current->code . ": " . $current->message . "\n"; $current = $current->next; $idx++; } @@ -106,41 +106,41 @@ stream_test_errors('AUTO ERROR', [ ALL Error details: - Message: TestStream::stream_cast is not implemented! -- Code: NotImplemented (70) +- Code: 70 - Wrapper: user-space - Terminating: yes - Count: 2 - [0] NotImplemented: TestStream::stream_cast is not implemented! - [1] CastNotSupported: Cannot represent a stream of type user-space as a select()able descriptor + [0] 70: TestStream::stream_cast is not implemented! + [1] 101: Cannot represent a stream of type user-space as a select()able descriptor NON TERMINATING Error details: - Message: TestStream::stream_read - read 10 bytes more data than requested (8202 read, 8192 max) - excess data will be lost -- Code: UserspaceInvalidReturn (161) +- Code: 161 - Wrapper: user-space - Terminating: no - Count: 1 - [0] UserspaceInvalidReturn: TestStream::stream_read - read 10 bytes more data than requested (8202 read, 8192 max) - excess data will be lost + [0] 161: TestStream::stream_read - read 10 bytes more data than requested (8202 read, 8192 max) - excess data will be lost TERMINATING Error details: - Message: TestStream::stream_cast is not implemented! -- Code: NotImplemented (70) +- Code: 70 - Wrapper: user-space - Terminating: yes - Count: 2 - [0] NotImplemented: TestStream::stream_cast is not implemented! - [1] CastNotSupported: Cannot represent a stream of type user-space as a select()able descriptor + [0] 70: TestStream::stream_cast is not implemented! + [1] 101: Cannot represent a stream of type user-space as a select()able descriptor AUTO EXCEPTION EXCEPTION: TestStream::stream_cast is not implemented! Error details: - Message: TestStream::stream_read - read 10 bytes more data than requested (8202 read, 8192 max) - excess data will be lost -- Code: UserspaceInvalidReturn (161) +- Code: 161 - Wrapper: user-space - Terminating: no - Count: 1 - [0] UserspaceInvalidReturn: TestStream::stream_read - read 10 bytes more data than requested (8202 read, 8192 max) - excess data will be lost + [0] 161: TestStream::stream_read - read 10 bytes more data than requested (8202 read, 8192 max) - excess data will be lost AUTO ERROR @@ -151,8 +151,8 @@ Warning: stream_select(): TestStream::stream_cast is not implemented! in %s on l Warning: stream_select(): Cannot represent a stream of type user-space as a select()able descriptor in %s on line %d Error details: - Message: TestStream::stream_read - read 10 bytes more data than requested (8202 read, 8192 max) - excess data will be lost -- Code: UserspaceInvalidReturn (161) +- Code: 161 - Wrapper: user-space - Terminating: no - Count: 1 - [0] UserspaceInvalidReturn: TestStream::stream_read - read 10 bytes more data than requested (8202 read, 8192 max) - excess data will be lost + [0] 161: TestStream::stream_read - read 10 bytes more data than requested (8202 read, 8192 max) - excess data will be lost diff --git a/ext/standard/tests/streams/stream_errors_multi_store.phpt b/ext/standard/tests/streams/stream_errors_multi_store.phpt index eccfb065d563c..7df5b1f54062a 100644 --- a/ext/standard/tests/streams/stream_errors_multi_store.phpt +++ b/ext/standard/tests/streams/stream_errors_multi_store.phpt @@ -13,8 +13,8 @@ $stream = fopen('php://nonexistent', 'r', false, $context); $error = stream_get_last_error(); if ($error) { - echo "Has OpenFailed: " . ($error->hasCode(StreamErrorCode::OpenFailed) ? 'yes' : 'no') . "\n"; - echo "Has NotFound: " . ($error->hasCode(StreamErrorCode::NotFound) ? 'yes' : 'no') . "\n"; + echo "Has OpenFailed: " . ($error->hasCode(StreamError::CODE_OPEN_FAILED) ? 'yes' : 'no') . "\n"; + echo "Has NotFound: " . ($error->hasCode(StreamError::CODE_NOT_FOUND) ? 'yes' : 'no') . "\n"; } ?> diff --git a/ext/standard/tests/streams/stream_errors_silent_with_handler.phpt b/ext/standard/tests/streams/stream_errors_silent_with_handler.phpt index 2416a15529aa5..f552737cf77c5 100644 --- a/ext/standard/tests/streams/stream_errors_silent_with_handler.phpt +++ b/ext/standard/tests/streams/stream_errors_silent_with_handler.phpt @@ -12,7 +12,7 @@ $context = stream_context_create([ $handler_called = true; echo "Handler called\n"; echo "Wrapper: " . $error->wrapperName . "\n"; - echo "Code: " . $error->code->name . "\n"; + echo "Code: " . $error->code . "\n"; echo "Message: " . $error->message . "\n"; echo "Param: " . ($error->param ?? 'null') . "\n"; echo "Terminating: " . ($error->terminating ? 'yes' : 'no') . "\n"; @@ -28,7 +28,7 @@ var_dump($handler_called); --EXPECT-- Handler called Wrapper: PHP -Code: OpenFailed +Code: 36 Message: Failed to open stream: operation failed Param: php://nonexistent Terminating: yes diff --git a/ext/standard/tests/streams/stream_errors_silent_with_storage.phpt b/ext/standard/tests/streams/stream_errors_silent_with_storage.phpt index 0d3d627001788..5d470572f4800 100644 --- a/ext/standard/tests/streams/stream_errors_silent_with_storage.phpt +++ b/ext/standard/tests/streams/stream_errors_silent_with_storage.phpt @@ -15,7 +15,7 @@ var_dump($stream); $error = stream_get_last_error(); if ($error) { echo "Has error: yes\n"; - echo "Error code: " . $error->code->name . "\n"; + echo "Error code: " . $error->code . "\n"; echo "Error wrapper: " . $error->wrapperName . "\n"; echo "Error message: " . $error->message . "\n"; } @@ -24,6 +24,6 @@ if ($error) { --EXPECT-- bool(false) Has error: yes -Error code: OpenFailed +Error code: 36 Error wrapper: PHP Error message: Failed to open stream: operation failed diff --git a/main/streams/php_stream_errors.h b/main/streams/php_stream_errors.h index 4d64e3905034a..936a76f3cfcab 100644 --- a/main/streams/php_stream_errors.h +++ b/main/streams/php_stream_errors.h @@ -61,102 +61,94 @@ BEGIN_EXTERN_C() #define STREAM_ERROR_CODE_USERSPACE_START 160 #define STREAM_ERROR_CODE_USERSPACE_END 170 -/* X-macro defining all error codes */ -#define PHP_STREAM_ERROR_CODES(V) \ - /* General errors */ \ - V(NONE, None, 0) \ - V(GENERIC, Generic, 1) \ - /* I/O operation errors (10-29) */ \ - V(READ_FAILED, ReadFailed, 10) \ - V(WRITE_FAILED, WriteFailed, 11) \ - V(SEEK_FAILED, SeekFailed, 12) \ - V(SEEK_NOT_SUPPORTED, SeekNotSupported, 13) \ - V(FLUSH_FAILED, FlushFailed, 14) \ - V(TRUNCATE_FAILED, TruncateFailed, 15) \ - V(CONNECT_FAILED, ConnectFailed, 16) \ - V(BIND_FAILED, BindFailed, 17) \ - V(LISTEN_FAILED, ListenFailed, 18) \ - V(NOT_WRITABLE, NotWritable, 19) \ - V(NOT_READABLE, NotReadable, 20) \ - /* File system operations (30-69) */ \ - V(DISABLED, Disabled, 30) \ - V(NOT_FOUND, NotFound, 31) \ - V(PERMISSION_DENIED, PermissionDenied, 32) \ - V(ALREADY_EXISTS, AlreadyExists, 33) \ - V(INVALID_PATH, InvalidPath, 34) \ - V(PATH_TOO_LONG, PathTooLong, 35) \ - V(OPEN_FAILED, OpenFailed, 36) \ - V(CREATE_FAILED, CreateFailed, 37) \ - V(DUP_FAILED, DupFailed, 38) \ - V(UNLINK_FAILED, UnlinkFailed, 39) \ - V(RENAME_FAILED, RenameFailed, 40) \ - V(MKDIR_FAILED, MkdirFailed, 41) \ - V(RMDIR_FAILED, RmdirFailed, 42) \ - V(STAT_FAILED, StatFailed, 43) \ - V(META_FAILED, MetaFailed, 44) \ - V(CHMOD_FAILED, ChmodFailed, 45) \ - V(CHOWN_FAILED, ChownFailed, 46) \ - V(COPY_FAILED, CopyFailed, 47) \ - V(TOUCH_FAILED, TouchFailed, 48) \ - V(INVALID_MODE, InvalidMode, 49) \ - V(INVALID_META, InvalidMeta, 50) \ - V(MODE_NOT_SUPPORTED, ModeNotSupported, 51) \ - V(READONLY, Readonly, 52) \ - V(RECURSION_DETECTED, RecursionDetected, 53) \ - /* Wrapper/protocol operations (70-89) */ \ - V(NOT_IMPLEMENTED, NotImplemented, 70) \ - V(NO_OPENER, NoOpener, 71) \ - V(PERSISTENT_NOT_SUPPORTED, PersistentNotSupported, 72) \ - V(WRAPPER_NOT_FOUND, WrapperNotFound, 73) \ - V(WRAPPER_DISABLED, WrapperDisabled, 74) \ - V(PROTOCOL_UNSUPPORTED, ProtocolUnsupported, 75) \ - V(WRAPPER_REGISTRATION_FAILED, WrapperRegistrationFailed, 76) \ - V(WRAPPER_UNREGISTRATION_FAILED, WrapperUnregistrationFailed, 77) \ - V(WRAPPER_RESTORATION_FAILED, WrapperRestorationFailed, 78) \ - /* Filter operations (90-99) */ \ - V(FILTER_NOT_FOUND, FilterNotFound, 90) \ - V(FILTER_FAILED, FilterFailed, 91) \ - /* Cast/conversion operations (100-109) */ \ - V(CAST_FAILED, CastFailed, 100) \ - V(CAST_NOT_SUPPORTED, CastNotSupported, 101) \ - V(MAKE_SEEKABLE_FAILED, MakeSeekableFailed, 102) \ - V(BUFFERED_DATA_LOST, BufferedDataLost, 103) \ - /* Network/socket operations (110-129) */ \ - V(NETWORK_SEND_FAILED, NetworkSendFailed, 110) \ - V(NETWORK_RECV_FAILED, NetworkRecvFailed, 111) \ - V(SSL_NOT_SUPPORTED, SslNotSupported, 112) \ - V(RESUMPTION_FAILED, ResumptionFailed, 113) \ - V(SOCKET_PATH_TOO_LONG, SocketPathTooLong, 114) \ - V(OOB_NOT_SUPPORTED, OobNotSupported, 115) \ - V(PROTOCOL_ERROR, ProtocolError, 116) \ - V(INVALID_URL, InvalidUrl, 117) \ - V(INVALID_RESPONSE, InvalidResponse, 118) \ - V(INVALID_HEADER, InvalidHeader, 119) \ - V(INVALID_PARAM, InvalidParam, 120) \ - V(REDIRECT_LIMIT, RedirectLimit, 121) \ - V(AUTH_FAILED, AuthFailed, 122) \ - /* Encoding/decoding/archiving operations (130-139) */ \ - V(ARCHIVING_FAILED, ArchivingFailed, 130) \ - V(ENCODING_FAILED, EncodingFailed, 131) \ - V(DECODING_FAILED, DecodingFailed, 132) \ - V(INVALID_FORMAT, InvalidFormat, 133) \ - /* Resource/allocation operations (140-149) */ \ - V(ALLOCATION_FAILED, AllocationFailed, 140) \ - V(TEMPORARY_FILE_FAILED, TemporaryFileFailed, 141) \ - /* Locking operations (150-159) */ \ - V(LOCK_FAILED, LockFailed, 150) \ - V(LOCK_NOT_SUPPORTED, LockNotSupported, 151) \ - /* Userspace stream operations (160-169) */ \ - V(USERSPACE_NOT_IMPLEMENTED, UserspaceNotImplemented, 160) \ - V(USERSPACE_INVALID_RETURN, UserspaceInvalidReturn, 161) \ - V(USERSPACE_CALL_FAILED, UserspaceCallFailed, 162) - -/* Generate C enum for internal use */ -typedef enum _StreamErrorCode { -#define V(uc_name, name, val) STREAM_ERROR_CODE_##uc_name = val, - PHP_STREAM_ERROR_CODES(V) -#undef V -} StreamErrorCode; +/* Error codes - exposed as StreamError::ERROR_CODE_* class constants */ +/* General errors */ +#define STREAM_ERROR_CODE_NONE 0 +#define STREAM_ERROR_CODE_GENERIC 1 +/* I/O operation errors (10-29) */ +#define STREAM_ERROR_CODE_READ_FAILED 10 +#define STREAM_ERROR_CODE_WRITE_FAILED 11 +#define STREAM_ERROR_CODE_SEEK_FAILED 12 +#define STREAM_ERROR_CODE_SEEK_NOT_SUPPORTED 13 +#define STREAM_ERROR_CODE_FLUSH_FAILED 14 +#define STREAM_ERROR_CODE_TRUNCATE_FAILED 15 +#define STREAM_ERROR_CODE_CONNECT_FAILED 16 +#define STREAM_ERROR_CODE_BIND_FAILED 17 +#define STREAM_ERROR_CODE_LISTEN_FAILED 18 +#define STREAM_ERROR_CODE_NOT_WRITABLE 19 +#define STREAM_ERROR_CODE_NOT_READABLE 20 +/* File system operations (30-69) */ +#define STREAM_ERROR_CODE_DISABLED 30 +#define STREAM_ERROR_CODE_NOT_FOUND 31 +#define STREAM_ERROR_CODE_PERMISSION_DENIED 32 +#define STREAM_ERROR_CODE_ALREADY_EXISTS 33 +#define STREAM_ERROR_CODE_INVALID_PATH 34 +#define STREAM_ERROR_CODE_PATH_TOO_LONG 35 +#define STREAM_ERROR_CODE_OPEN_FAILED 36 +#define STREAM_ERROR_CODE_CREATE_FAILED 37 +#define STREAM_ERROR_CODE_DUP_FAILED 38 +#define STREAM_ERROR_CODE_UNLINK_FAILED 39 +#define STREAM_ERROR_CODE_RENAME_FAILED 40 +#define STREAM_ERROR_CODE_MKDIR_FAILED 41 +#define STREAM_ERROR_CODE_RMDIR_FAILED 42 +#define STREAM_ERROR_CODE_STAT_FAILED 43 +#define STREAM_ERROR_CODE_META_FAILED 44 +#define STREAM_ERROR_CODE_CHMOD_FAILED 45 +#define STREAM_ERROR_CODE_CHOWN_FAILED 46 +#define STREAM_ERROR_CODE_COPY_FAILED 47 +#define STREAM_ERROR_CODE_TOUCH_FAILED 48 +#define STREAM_ERROR_CODE_INVALID_MODE 49 +#define STREAM_ERROR_CODE_INVALID_META 50 +#define STREAM_ERROR_CODE_MODE_NOT_SUPPORTED 51 +#define STREAM_ERROR_CODE_READONLY 52 +#define STREAM_ERROR_CODE_RECURSION_DETECTED 53 +/* Wrapper/protocol operations (70-89) */ +#define STREAM_ERROR_CODE_NOT_IMPLEMENTED 70 +#define STREAM_ERROR_CODE_NO_OPENER 71 +#define STREAM_ERROR_CODE_PERSISTENT_NOT_SUPPORTED 72 +#define STREAM_ERROR_CODE_WRAPPER_NOT_FOUND 73 +#define STREAM_ERROR_CODE_WRAPPER_DISABLED 74 +#define STREAM_ERROR_CODE_PROTOCOL_UNSUPPORTED 75 +#define STREAM_ERROR_CODE_WRAPPER_REGISTRATION_FAILED 76 +#define STREAM_ERROR_CODE_WRAPPER_UNREGISTRATION_FAILED 77 +#define STREAM_ERROR_CODE_WRAPPER_RESTORATION_FAILED 78 +/* Filter operations (90-99) */ +#define STREAM_ERROR_CODE_FILTER_NOT_FOUND 90 +#define STREAM_ERROR_CODE_FILTER_FAILED 91 +/* Cast/conversion operations (100-109) */ +#define STREAM_ERROR_CODE_CAST_FAILED 100 +#define STREAM_ERROR_CODE_CAST_NOT_SUPPORTED 101 +#define STREAM_ERROR_CODE_MAKE_SEEKABLE_FAILED 102 +#define STREAM_ERROR_CODE_BUFFERED_DATA_LOST 103 +/* Network/socket operations (110-129) */ +#define STREAM_ERROR_CODE_NETWORK_SEND_FAILED 110 +#define STREAM_ERROR_CODE_NETWORK_RECV_FAILED 111 +#define STREAM_ERROR_CODE_SSL_NOT_SUPPORTED 112 +#define STREAM_ERROR_CODE_RESUMPTION_FAILED 113 +#define STREAM_ERROR_CODE_SOCKET_PATH_TOO_LONG 114 +#define STREAM_ERROR_CODE_OOB_NOT_SUPPORTED 115 +#define STREAM_ERROR_CODE_PROTOCOL_ERROR 116 +#define STREAM_ERROR_CODE_INVALID_URL 117 +#define STREAM_ERROR_CODE_INVALID_RESPONSE 118 +#define STREAM_ERROR_CODE_INVALID_HEADER 119 +#define STREAM_ERROR_CODE_INVALID_PARAM 120 +#define STREAM_ERROR_CODE_REDIRECT_LIMIT 121 +#define STREAM_ERROR_CODE_AUTH_FAILED 122 +/* Encoding/decoding/archiving operations (130-139) */ +#define STREAM_ERROR_CODE_ARCHIVING_FAILED 130 +#define STREAM_ERROR_CODE_ENCODING_FAILED 131 +#define STREAM_ERROR_CODE_DECODING_FAILED 132 +#define STREAM_ERROR_CODE_INVALID_FORMAT 133 +/* Resource/allocation operations (140-149) */ +#define STREAM_ERROR_CODE_ALLOCATION_FAILED 140 +#define STREAM_ERROR_CODE_TEMPORARY_FILE_FAILED 141 +/* Locking operations (150-159) */ +#define STREAM_ERROR_CODE_LOCK_FAILED 150 +#define STREAM_ERROR_CODE_LOCK_NOT_SUPPORTED 151 +/* Userspace stream operations (160-169) */ +#define STREAM_ERROR_CODE_USERSPACE_NOT_IMPLEMENTED 160 +#define STREAM_ERROR_CODE_USERSPACE_INVALID_RETURN 161 +#define STREAM_ERROR_CODE_USERSPACE_CALL_FAILED 162 /* Wrapper name for PHP errors */ #define PHP_STREAM_ERROR_WRAPPER_DEFAULT_NAME ":na" @@ -166,7 +158,7 @@ typedef enum _StreamErrorCode { /* Error entry in chain */ typedef struct _php_stream_error_entry { zend_string *message; - StreamErrorCode code; + int code; char *wrapper_name; char *param; char *docref; diff --git a/main/streams/stream_errors.c b/main/streams/stream_errors.c index 4e2b68efd82fb..cd10e7eb515c0 100644 --- a/main/streams/stream_errors.c +++ b/main/streams/stream_errors.c @@ -24,22 +24,13 @@ #include "stream_errors_arginfo.h" /* Class entries */ -static zend_class_entry *php_ce_stream_error_code; static zend_class_entry *php_ce_stream_error_mode; static zend_class_entry *php_ce_stream_error_store; static zend_class_entry *php_ce_stream_error; static zend_class_entry *php_ce_stream_exception; -/* Lookup table for error code to case name */ -static const char *const php_stream_error_code_names[200] = { -#define V(uc_name, name, val) [val] = #name, - PHP_STREAM_ERROR_CODES(V) -#undef V -}; - /* Forward declarations */ static void php_stream_error_entry_free(php_stream_error_entry *entry); -static bool php_stream_error_code_in_range(zval *this_zv, int start, int end); /* Context option helpers */ @@ -265,7 +256,7 @@ PHPAPI php_stream_error_operation *php_stream_error_operation_begin(void) return op; } -static void php_stream_error_add(StreamErrorCode code, const char *wrapper_name, +static void php_stream_error_add(int code, const char *wrapper_name, zend_string *message, const char *docref, char *param, int severity, bool terminating) { php_stream_error_operation *op = FG(stream_error_state).current_operation; @@ -331,7 +322,7 @@ static void php_stream_throw_exception_with_errors(php_stream_error_operation *o zend_update_property_string(php_ce_stream_exception, Z_OBJ(ex), ZEND_STRL("message"), ZSTR_VAL(op->first_error->message)); - /* Set code from first error enum value */ + /* Set code from first error code value */ zend_update_property_long(php_ce_stream_exception, Z_OBJ(ex), ZEND_STRL("code"), (zend_long) op->first_error->code); @@ -854,7 +845,7 @@ PHPAPI void php_stream_tidy_wrapper_error_log(php_stream_wrapper *wrapper) } } -/* StreamError object creation - no enum cache */ +/* StreamError object creation */ PHPAPI void php_stream_error_create_object(zval *zv, php_stream_error_entry *entry) { @@ -865,29 +856,9 @@ PHPAPI void php_stream_error_create_object(zval *zv, php_stream_error_entry *ent object_init_ex(zv, php_ce_stream_error); - /* Get enum case by value using lookup array */ - const char *case_name = NULL; - int code_value = (int) entry->code; - - if (code_value >= 0 - && code_value < (int) (sizeof(php_stream_error_code_names) - / sizeof(php_stream_error_code_names[0]))) { - case_name = php_stream_error_code_names[code_value]; - } - - if (!case_name) { - case_name = "Generic"; - } - - zend_object *enum_obj = zend_enum_get_case_cstr(php_ce_stream_error_code, case_name); - ZEND_ASSERT(enum_obj != NULL); - - zval code_enum; - ZVAL_OBJ(&code_enum, enum_obj); - GC_ADDREF(enum_obj); - - zend_update_property(php_ce_stream_error, Z_OBJ_P(zv), ZEND_STRL("code"), &code_enum); - zval_ptr_dtor(&code_enum); + /* Set code as integer */ + zend_update_property_long( + php_ce_stream_error, Z_OBJ_P(zv), ZEND_STRL("code"), (zend_long) entry->code); /* Set other properties */ zend_update_property_str( @@ -919,88 +890,24 @@ PHPAPI void php_stream_error_create_object(zval *zv, php_stream_error_entry *ent } } -/* StreamError methods */ - -PHP_METHOD(StreamError, hasCode) -{ - zval *search_code; - - ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_OBJECT_OF_CLASS(search_code, php_ce_stream_error_code) - ZEND_PARSE_PARAMETERS_END(); - - zval *current_error_zv = ZEND_THIS; - - while (Z_TYPE_P(current_error_zv) == IS_OBJECT) { - zval *code_zv = zend_read_property( - php_ce_stream_error, Z_OBJ_P(current_error_zv), ZEND_STRL("code"), 1, NULL); - - /* Compare enum objects */ - if (Z_TYPE_P(code_zv) == IS_OBJECT && Z_OBJ_P(code_zv) == Z_OBJ_P(search_code)) { - RETURN_TRUE; - } - - /* Move to next error */ - current_error_zv = zend_read_property( - php_ce_stream_error, Z_OBJ_P(current_error_zv), ZEND_STRL("next"), 1, NULL); - - if (Z_TYPE_P(current_error_zv) != IS_OBJECT) { - break; - } - } - - RETURN_FALSE; -} - -PHP_METHOD(StreamError, count) -{ - ZEND_PARSE_PARAMETERS_NONE(); - - zend_long count = 1; - zval *current_error_zv = ZEND_THIS; - - while (1) { - current_error_zv = zend_read_property( - php_ce_stream_error, Z_OBJ_P(current_error_zv), ZEND_STRL("next"), 1, NULL); - - if (Z_TYPE_P(current_error_zv) != IS_OBJECT) { - break; - } - - count++; - } - - RETURN_LONG(count); -} - -/* StreamException methods */ - -PHP_METHOD(StreamException, getError) -{ - ZEND_PARSE_PARAMETERS_NONE(); - - zval *error = zend_read_property( - php_ce_stream_exception, Z_OBJ_P(ZEND_THIS), ZEND_STRL("error"), 1, NULL); - - RETURN_COPY(error); -} - -/* StreamErrorCode helper */ +/* Helper to check if error code is in range */ static bool php_stream_error_code_in_range(zval *this_zv, int start, int end) { - zval *backing = zend_enum_fetch_case_value(Z_OBJ_P(this_zv)); - if (!backing || Z_TYPE_P(backing) != IS_LONG) { + zval *code_zv = zend_read_property( + php_ce_stream_error, Z_OBJ_P(this_zv), ZEND_STRL("code"), 1, NULL); + + if (!code_zv || Z_TYPE_P(code_zv) != IS_LONG) { return false; } - zend_long value = Z_LVAL_P(backing); + zend_long value = Z_LVAL_P(code_zv); return value >= start && value < end; } -/* StreamErrorCode methods */ +/* StreamError methods */ -PHP_METHOD(StreamErrorCode, isIoError) +PHP_METHOD(StreamError, isIoError) { ZEND_PARSE_PARAMETERS_NONE(); @@ -1008,7 +915,7 @@ PHP_METHOD(StreamErrorCode, isIoError) ZEND_THIS, STREAM_ERROR_CODE_IO_START, STREAM_ERROR_CODE_IO_END)); } -PHP_METHOD(StreamErrorCode, isFileSystemError) +PHP_METHOD(StreamError, isFileSystemError) { ZEND_PARSE_PARAMETERS_NONE(); @@ -1016,7 +923,7 @@ PHP_METHOD(StreamErrorCode, isFileSystemError) ZEND_THIS, STREAM_ERROR_CODE_FILESYSTEM_START, STREAM_ERROR_CODE_FILESYSTEM_END)); } -PHP_METHOD(StreamErrorCode, isWrapperError) +PHP_METHOD(StreamError, isWrapperError) { ZEND_PARSE_PARAMETERS_NONE(); @@ -1024,7 +931,7 @@ PHP_METHOD(StreamErrorCode, isWrapperError) ZEND_THIS, STREAM_ERROR_CODE_WRAPPER_START, STREAM_ERROR_CODE_WRAPPER_END)); } -PHP_METHOD(StreamErrorCode, isFilterError) +PHP_METHOD(StreamError, isFilterError) { ZEND_PARSE_PARAMETERS_NONE(); @@ -1032,7 +939,7 @@ PHP_METHOD(StreamErrorCode, isFilterError) ZEND_THIS, STREAM_ERROR_CODE_FILTER_START, STREAM_ERROR_CODE_FILTER_END)); } -PHP_METHOD(StreamErrorCode, isCastError) +PHP_METHOD(StreamError, isCastError) { ZEND_PARSE_PARAMETERS_NONE(); @@ -1040,7 +947,7 @@ PHP_METHOD(StreamErrorCode, isCastError) ZEND_THIS, STREAM_ERROR_CODE_CAST_START, STREAM_ERROR_CODE_CAST_END)); } -PHP_METHOD(StreamErrorCode, isNetworkError) +PHP_METHOD(StreamError, isNetworkError) { ZEND_PARSE_PARAMETERS_NONE(); @@ -1048,7 +955,7 @@ PHP_METHOD(StreamErrorCode, isNetworkError) ZEND_THIS, STREAM_ERROR_CODE_NETWORK_START, STREAM_ERROR_CODE_NETWORK_END)); } -PHP_METHOD(StreamErrorCode, isEncodingError) +PHP_METHOD(StreamError, isEncodingError) { ZEND_PARSE_PARAMETERS_NONE(); @@ -1056,7 +963,7 @@ PHP_METHOD(StreamErrorCode, isEncodingError) ZEND_THIS, STREAM_ERROR_CODE_ENCODING_START, STREAM_ERROR_CODE_ENCODING_END)); } -PHP_METHOD(StreamErrorCode, isResourceError) +PHP_METHOD(StreamError, isResourceError) { ZEND_PARSE_PARAMETERS_NONE(); @@ -1064,7 +971,7 @@ PHP_METHOD(StreamErrorCode, isResourceError) ZEND_THIS, STREAM_ERROR_CODE_RESOURCE_START, STREAM_ERROR_CODE_RESOURCE_END)); } -PHP_METHOD(StreamErrorCode, isLockError) +PHP_METHOD(StreamError, isLockError) { ZEND_PARSE_PARAMETERS_NONE(); @@ -1072,7 +979,7 @@ PHP_METHOD(StreamErrorCode, isLockError) ZEND_THIS, STREAM_ERROR_CODE_LOCK_START, STREAM_ERROR_CODE_LOCK_END)); } -PHP_METHOD(StreamErrorCode, isUserspaceError) +PHP_METHOD(StreamError, isUserspaceError) { ZEND_PARSE_PARAMETERS_NONE(); @@ -1080,25 +987,78 @@ PHP_METHOD(StreamErrorCode, isUserspaceError) ZEND_THIS, STREAM_ERROR_CODE_USERSPACE_START, STREAM_ERROR_CODE_USERSPACE_END)); } +PHP_METHOD(StreamError, hasCode) +{ + zend_long search_code; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_LONG(search_code) + ZEND_PARSE_PARAMETERS_END(); + + zval *current_error_zv = ZEND_THIS; + + while (Z_TYPE_P(current_error_zv) == IS_OBJECT) { + zval *code_zv = zend_read_property( + php_ce_stream_error, Z_OBJ_P(current_error_zv), ZEND_STRL("code"), 1, NULL); + + /* Compare integer code values */ + if (Z_TYPE_P(code_zv) == IS_LONG && Z_LVAL_P(code_zv) == search_code) { + RETURN_TRUE; + } + + /* Move to next error */ + current_error_zv = zend_read_property( + php_ce_stream_error, Z_OBJ_P(current_error_zv), ZEND_STRL("next"), 1, NULL); + + if (Z_TYPE_P(current_error_zv) != IS_OBJECT) { + break; + } + } + + RETURN_FALSE; +} + +PHP_METHOD(StreamError, count) +{ + ZEND_PARSE_PARAMETERS_NONE(); + + zend_long count = 1; + zval *current_error_zv = ZEND_THIS; + + while (1) { + current_error_zv = zend_read_property( + php_ce_stream_error, Z_OBJ_P(current_error_zv), ZEND_STRL("next"), 1, NULL); + + if (Z_TYPE_P(current_error_zv) != IS_OBJECT) { + break; + } + + count++; + } + + RETURN_LONG(count); +} + +/* StreamException methods */ + +PHP_METHOD(StreamException, getError) +{ + ZEND_PARSE_PARAMETERS_NONE(); + + zval *error = zend_read_property( + php_ce_stream_exception, Z_OBJ_P(ZEND_THIS), ZEND_STRL("error"), 1, NULL); + + RETURN_COPY(error); +} + /* Module init */ PHP_MINIT_FUNCTION(stream_errors) { /* Register enums */ - php_ce_stream_error_code = register_class_StreamErrorCode(); php_ce_stream_error_mode = register_class_StreamErrorMode(); php_ce_stream_error_store = register_class_StreamErrorStore(); - /* Add cases to StreamErrorCode */ -#define V(uc_name, name, val) \ - { \ - zval enum_case_value; \ - ZVAL_LONG(&enum_case_value, val); \ - zend_enum_add_case_cstr(php_ce_stream_error_code, #name, &enum_case_value); \ - } - PHP_STREAM_ERROR_CODES(V) -#undef V - /* Register classes */ php_ce_stream_error = register_class_StreamError(); php_ce_stream_exception = register_class_StreamException(zend_ce_exception); diff --git a/main/streams/stream_errors.stub.php b/main/streams/stream_errors.stub.php index 8b6b549a68eb7..eae801f6c5473 100644 --- a/main/streams/stream_errors.stub.php +++ b/main/streams/stream_errors.stub.php @@ -2,31 +2,6 @@ /** @generate-class-entries static */ -enum StreamErrorCode: int -{ - // Error code cases registered in code - - public function isIoError(): bool {} - - public function isFileSystemError(): bool {} - - public function isWrapperError(): bool {} - - public function isFilterError(): bool {} - - public function isCastError(): bool {} - - public function isNetworkError(): bool {} - - public function isEncodingError(): bool {} - - public function isResourceError(): bool {} - - public function isLockError(): bool {} - - public function isUserspaceError(): bool {} -} - enum StreamErrorMode { case Error; @@ -45,7 +20,181 @@ enum StreamErrorStore final readonly class StreamError { - public StreamErrorCode $code; + /* General errors */ + /** @cvalue STREAM_ERROR_CODE_NONE */ + public const int CODE_NONE = UNKNOWN; + /** @cvalue STREAM_ERROR_CODE_GENERIC */ + public const int CODE_GENERIC = UNKNOWN; + + /* I/O operation errors (10-29) */ + /** @cvalue STREAM_ERROR_CODE_READ_FAILED */ + public const int CODE_READ_FAILED = UNKNOWN; + /** @cvalue STREAM_ERROR_CODE_WRITE_FAILED */ + public const int CODE_WRITE_FAILED = UNKNOWN; + /** @cvalue STREAM_ERROR_CODE_SEEK_FAILED */ + public const int CODE_SEEK_FAILED = UNKNOWN; + /** @cvalue STREAM_ERROR_CODE_SEEK_NOT_SUPPORTED */ + public const int CODE_SEEK_NOT_SUPPORTED = UNKNOWN; + /** @cvalue STREAM_ERROR_CODE_FLUSH_FAILED */ + public const int CODE_FLUSH_FAILED = UNKNOWN; + /** @cvalue STREAM_ERROR_CODE_TRUNCATE_FAILED */ + public const int CODE_TRUNCATE_FAILED = UNKNOWN; + /** @cvalue STREAM_ERROR_CODE_CONNECT_FAILED */ + public const int CODE_CONNECT_FAILED = UNKNOWN; + /** @cvalue STREAM_ERROR_CODE_BIND_FAILED */ + public const int CODE_BIND_FAILED = UNKNOWN; + /** @cvalue STREAM_ERROR_CODE_LISTEN_FAILED */ + public const int CODE_LISTEN_FAILED = UNKNOWN; + /** @cvalue STREAM_ERROR_CODE_NOT_WRITABLE */ + public const int CODE_NOT_WRITABLE = UNKNOWN; + /** @cvalue STREAM_ERROR_CODE_NOT_READABLE */ + public const int CODE_NOT_READABLE = UNKNOWN; + + /* File system operations (30-69) */ + /** @cvalue STREAM_ERROR_CODE_DISABLED */ + public const int CODE_DISABLED = UNKNOWN; + /** @cvalue STREAM_ERROR_CODE_NOT_FOUND */ + public const int CODE_NOT_FOUND = UNKNOWN; + /** @cvalue STREAM_ERROR_CODE_PERMISSION_DENIED */ + public const int CODE_PERMISSION_DENIED = UNKNOWN; + /** @cvalue STREAM_ERROR_CODE_ALREADY_EXISTS */ + public const int CODE_ALREADY_EXISTS = UNKNOWN; + /** @cvalue STREAM_ERROR_CODE_INVALID_PATH */ + public const int CODE_INVALID_PATH = UNKNOWN; + /** @cvalue STREAM_ERROR_CODE_PATH_TOO_LONG */ + public const int CODE_PATH_TOO_LONG = UNKNOWN; + /** @cvalue STREAM_ERROR_CODE_OPEN_FAILED */ + public const int CODE_OPEN_FAILED = UNKNOWN; + /** @cvalue STREAM_ERROR_CODE_CREATE_FAILED */ + public const int CODE_CREATE_FAILED = UNKNOWN; + /** @cvalue STREAM_ERROR_CODE_DUP_FAILED */ + public const int CODE_DUP_FAILED = UNKNOWN; + /** @cvalue STREAM_ERROR_CODE_UNLINK_FAILED */ + public const int CODE_UNLINK_FAILED = UNKNOWN; + /** @cvalue STREAM_ERROR_CODE_RENAME_FAILED */ + public const int CODE_RENAME_FAILED = UNKNOWN; + /** @cvalue STREAM_ERROR_CODE_MKDIR_FAILED */ + public const int CODE_MKDIR_FAILED = UNKNOWN; + /** @cvalue STREAM_ERROR_CODE_RMDIR_FAILED */ + public const int CODE_RMDIR_FAILED = UNKNOWN; + /** @cvalue STREAM_ERROR_CODE_STAT_FAILED */ + public const int CODE_STAT_FAILED = UNKNOWN; + /** @cvalue STREAM_ERROR_CODE_META_FAILED */ + public const int CODE_META_FAILED = UNKNOWN; + /** @cvalue STREAM_ERROR_CODE_CHMOD_FAILED */ + public const int CODE_CHMOD_FAILED = UNKNOWN; + /** @cvalue STREAM_ERROR_CODE_CHOWN_FAILED */ + public const int CODE_CHOWN_FAILED = UNKNOWN; + /** @cvalue STREAM_ERROR_CODE_COPY_FAILED */ + public const int CODE_COPY_FAILED = UNKNOWN; + /** @cvalue STREAM_ERROR_CODE_TOUCH_FAILED */ + public const int CODE_TOUCH_FAILED = UNKNOWN; + /** @cvalue STREAM_ERROR_CODE_INVALID_MODE */ + public const int CODE_INVALID_MODE = UNKNOWN; + /** @cvalue STREAM_ERROR_CODE_INVALID_META */ + public const int CODE_INVALID_META = UNKNOWN; + /** @cvalue STREAM_ERROR_CODE_MODE_NOT_SUPPORTED */ + public const int CODE_MODE_NOT_SUPPORTED = UNKNOWN; + /** @cvalue STREAM_ERROR_CODE_READONLY */ + public const int CODE_READONLY = UNKNOWN; + /** @cvalue STREAM_ERROR_CODE_RECURSION_DETECTED */ + public const int CODE_RECURSION_DETECTED = UNKNOWN; + + /* Wrapper/protocol operations (70-89) */ + /** @cvalue STREAM_ERROR_CODE_NOT_IMPLEMENTED */ + public const int CODE_NOT_IMPLEMENTED = UNKNOWN; + /** @cvalue STREAM_ERROR_CODE_NO_OPENER */ + public const int CODE_NO_OPENER = UNKNOWN; + /** @cvalue STREAM_ERROR_CODE_PERSISTENT_NOT_SUPPORTED */ + public const int CODE_PERSISTENT_NOT_SUPPORTED = UNKNOWN; + /** @cvalue STREAM_ERROR_CODE_WRAPPER_NOT_FOUND */ + public const int CODE_WRAPPER_NOT_FOUND = UNKNOWN; + /** @cvalue STREAM_ERROR_CODE_WRAPPER_DISABLED */ + public const int CODE_WRAPPER_DISABLED = UNKNOWN; + /** @cvalue STREAM_ERROR_CODE_PROTOCOL_UNSUPPORTED */ + public const int CODE_PROTOCOL_UNSUPPORTED = UNKNOWN; + /** @cvalue STREAM_ERROR_CODE_WRAPPER_REGISTRATION_FAILED */ + public const int CODE_WRAPPER_REGISTRATION_FAILED = UNKNOWN; + /** @cvalue STREAM_ERROR_CODE_WRAPPER_UNREGISTRATION_FAILED */ + public const int CODE_WRAPPER_UNREGISTRATION_FAILED = UNKNOWN; + /** @cvalue STREAM_ERROR_CODE_WRAPPER_RESTORATION_FAILED */ + public const int CODE_WRAPPER_RESTORATION_FAILED = UNKNOWN; + + /* Filter operations (90-99) */ + /** @cvalue STREAM_ERROR_CODE_FILTER_NOT_FOUND */ + public const int CODE_FILTER_NOT_FOUND = UNKNOWN; + /** @cvalue STREAM_ERROR_CODE_FILTER_FAILED */ + public const int CODE_FILTER_FAILED = UNKNOWN; + + /* Cast/conversion operations (100-109) */ + /** @cvalue STREAM_ERROR_CODE_CAST_FAILED */ + public const int CODE_CAST_FAILED = UNKNOWN; + /** @cvalue STREAM_ERROR_CODE_CAST_NOT_SUPPORTED */ + public const int CODE_CAST_NOT_SUPPORTED = UNKNOWN; + /** @cvalue STREAM_ERROR_CODE_MAKE_SEEKABLE_FAILED */ + public const int CODE_MAKE_SEEKABLE_FAILED = UNKNOWN; + /** @cvalue STREAM_ERROR_CODE_BUFFERED_DATA_LOST */ + public const int CODE_BUFFERED_DATA_LOST = UNKNOWN; + + /* Network/socket operations (110-129) */ + /** @cvalue STREAM_ERROR_CODE_NETWORK_SEND_FAILED */ + public const int CODE_NETWORK_SEND_FAILED = UNKNOWN; + /** @cvalue STREAM_ERROR_CODE_NETWORK_RECV_FAILED */ + public const int CODE_NETWORK_RECV_FAILED = UNKNOWN; + /** @cvalue STREAM_ERROR_CODE_SSL_NOT_SUPPORTED */ + public const int CODE_SSL_NOT_SUPPORTED = UNKNOWN; + /** @cvalue STREAM_ERROR_CODE_RESUMPTION_FAILED */ + public const int CODE_RESUMPTION_FAILED = UNKNOWN; + /** @cvalue STREAM_ERROR_CODE_SOCKET_PATH_TOO_LONG */ + public const int CODE_SOCKET_PATH_TOO_LONG = UNKNOWN; + /** @cvalue STREAM_ERROR_CODE_OOB_NOT_SUPPORTED */ + public const int CODE_OOB_NOT_SUPPORTED = UNKNOWN; + /** @cvalue STREAM_ERROR_CODE_PROTOCOL_ERROR */ + public const int CODE_PROTOCOL_ERROR = UNKNOWN; + /** @cvalue STREAM_ERROR_CODE_INVALID_URL */ + public const int CODE_INVALID_URL = UNKNOWN; + /** @cvalue STREAM_ERROR_CODE_INVALID_RESPONSE */ + public const int CODE_INVALID_RESPONSE = UNKNOWN; + /** @cvalue STREAM_ERROR_CODE_INVALID_HEADER */ + public const int CODE_INVALID_HEADER = UNKNOWN; + /** @cvalue STREAM_ERROR_CODE_INVALID_PARAM */ + public const int CODE_INVALID_PARAM = UNKNOWN; + /** @cvalue STREAM_ERROR_CODE_REDIRECT_LIMIT */ + public const int CODE_REDIRECT_LIMIT = UNKNOWN; + /** @cvalue STREAM_ERROR_CODE_AUTH_FAILED */ + public const int CODE_AUTH_FAILED = UNKNOWN; + + /* Encoding/decoding/archiving operations (130-139) */ + /** @cvalue STREAM_ERROR_CODE_ARCHIVING_FAILED */ + public const int CODE_ARCHIVING_FAILED = UNKNOWN; + /** @cvalue STREAM_ERROR_CODE_ENCODING_FAILED */ + public const int CODE_ENCODING_FAILED = UNKNOWN; + /** @cvalue STREAM_ERROR_CODE_DECODING_FAILED */ + public const int CODE_DECODING_FAILED = UNKNOWN; + /** @cvalue STREAM_ERROR_CODE_INVALID_FORMAT */ + public const int CODE_INVALID_FORMAT = UNKNOWN; + + /* Resource/allocation operations (140-149) */ + /** @cvalue STREAM_ERROR_CODE_ALLOCATION_FAILED */ + public const int CODE_ALLOCATION_FAILED = UNKNOWN; + /** @cvalue STREAM_ERROR_CODE_TEMPORARY_FILE_FAILED */ + public const int CODE_TEMPORARY_FILE_FAILED = UNKNOWN; + + /* Locking operations (150-159) */ + /** @cvalue STREAM_ERROR_CODE_LOCK_FAILED */ + public const int CODE_LOCK_FAILED = UNKNOWN; + /** @cvalue STREAM_ERROR_CODE_LOCK_NOT_SUPPORTED */ + public const int CODE_LOCK_NOT_SUPPORTED = UNKNOWN; + + /* Userspace stream operations (160-169) */ + /** @cvalue STREAM_ERROR_CODE_USERSPACE_NOT_IMPLEMENTED */ + public const int CODE_USERSPACE_NOT_IMPLEMENTED = UNKNOWN; + /** @cvalue STREAM_ERROR_CODE_USERSPACE_INVALID_RETURN */ + public const int CODE_USERSPACE_INVALID_RETURN = UNKNOWN; + /** @cvalue STREAM_ERROR_CODE_USERSPACE_CALL_FAILED */ + public const int CODE_USERSPACE_CALL_FAILED = UNKNOWN; + + public int $code; public string $message; public string $wrapperName; public int $severity; @@ -53,7 +202,27 @@ enum StreamErrorStore public ?string $param; public ?StreamError $next; - public function hasCode(StreamErrorCode $code): bool {} + public function isIoError(): bool {} + + public function isFileSystemError(): bool {} + + public function isWrapperError(): bool {} + + public function isFilterError(): bool {} + + public function isCastError(): bool {} + + public function isNetworkError(): bool {} + + public function isEncodingError(): bool {} + + public function isResourceError(): bool {} + + public function isLockError(): bool {} + + public function isUserspaceError(): bool {} + + public function hasCode(int $code): bool {} public function count(): int {} } diff --git a/main/streams/stream_errors_arginfo.h b/main/streams/stream_errors_arginfo.h index 7fded66ec89d5..bd2412f2e73c2 100644 --- a/main/streams/stream_errors_arginfo.h +++ b/main/streams/stream_errors_arginfo.h @@ -1,29 +1,29 @@ -/* This is a generated file, edit the .stub.php file instead. - * Stub hash: 24a4229f4272983a6fb996ce136ea904183e14e0 */ +/* This is a generated file, edit stream_errors.stub.php instead. + * Stub hash: d6862fd09e088b7eb6cff766e812bb7246525b76 */ -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_StreamErrorCode_isIoError, 0, 0, _IS_BOOL, 0) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_StreamError_isIoError, 0, 0, _IS_BOOL, 0) ZEND_END_ARG_INFO() -#define arginfo_class_StreamErrorCode_isFileSystemError arginfo_class_StreamErrorCode_isIoError +#define arginfo_class_StreamError_isFileSystemError arginfo_class_StreamError_isIoError -#define arginfo_class_StreamErrorCode_isWrapperError arginfo_class_StreamErrorCode_isIoError +#define arginfo_class_StreamError_isWrapperError arginfo_class_StreamError_isIoError -#define arginfo_class_StreamErrorCode_isFilterError arginfo_class_StreamErrorCode_isIoError +#define arginfo_class_StreamError_isFilterError arginfo_class_StreamError_isIoError -#define arginfo_class_StreamErrorCode_isCastError arginfo_class_StreamErrorCode_isIoError +#define arginfo_class_StreamError_isCastError arginfo_class_StreamError_isIoError -#define arginfo_class_StreamErrorCode_isNetworkError arginfo_class_StreamErrorCode_isIoError +#define arginfo_class_StreamError_isNetworkError arginfo_class_StreamError_isIoError -#define arginfo_class_StreamErrorCode_isEncodingError arginfo_class_StreamErrorCode_isIoError +#define arginfo_class_StreamError_isEncodingError arginfo_class_StreamError_isIoError -#define arginfo_class_StreamErrorCode_isResourceError arginfo_class_StreamErrorCode_isIoError +#define arginfo_class_StreamError_isResourceError arginfo_class_StreamError_isIoError -#define arginfo_class_StreamErrorCode_isLockError arginfo_class_StreamErrorCode_isIoError +#define arginfo_class_StreamError_isLockError arginfo_class_StreamError_isIoError -#define arginfo_class_StreamErrorCode_isUserspaceError arginfo_class_StreamErrorCode_isIoError +#define arginfo_class_StreamError_isUserspaceError arginfo_class_StreamError_isIoError ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_StreamError_hasCode, 0, 1, _IS_BOOL, 0) - ZEND_ARG_OBJ_INFO(0, code, StreamErrorCode, 0) + ZEND_ARG_TYPE_INFO(0, code, IS_LONG, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_StreamError_count, 0, 0, IS_LONG, 0) @@ -32,35 +32,31 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_StreamException_getError, 0, 0, StreamError, 1) ZEND_END_ARG_INFO() -static ZEND_METHOD(StreamErrorCode, isIoError); -static ZEND_METHOD(StreamErrorCode, isFileSystemError); -static ZEND_METHOD(StreamErrorCode, isWrapperError); -static ZEND_METHOD(StreamErrorCode, isFilterError); -static ZEND_METHOD(StreamErrorCode, isCastError); -static ZEND_METHOD(StreamErrorCode, isNetworkError); -static ZEND_METHOD(StreamErrorCode, isEncodingError); -static ZEND_METHOD(StreamErrorCode, isResourceError); -static ZEND_METHOD(StreamErrorCode, isLockError); -static ZEND_METHOD(StreamErrorCode, isUserspaceError); +static ZEND_METHOD(StreamError, isIoError); +static ZEND_METHOD(StreamError, isFileSystemError); +static ZEND_METHOD(StreamError, isWrapperError); +static ZEND_METHOD(StreamError, isFilterError); +static ZEND_METHOD(StreamError, isCastError); +static ZEND_METHOD(StreamError, isNetworkError); +static ZEND_METHOD(StreamError, isEncodingError); +static ZEND_METHOD(StreamError, isResourceError); +static ZEND_METHOD(StreamError, isLockError); +static ZEND_METHOD(StreamError, isUserspaceError); static ZEND_METHOD(StreamError, hasCode); static ZEND_METHOD(StreamError, count); static ZEND_METHOD(StreamException, getError); -static const zend_function_entry class_StreamErrorCode_methods[] = { - ZEND_ME(StreamErrorCode, isIoError, arginfo_class_StreamErrorCode_isIoError, ZEND_ACC_PUBLIC) - ZEND_ME(StreamErrorCode, isFileSystemError, arginfo_class_StreamErrorCode_isFileSystemError, ZEND_ACC_PUBLIC) - ZEND_ME(StreamErrorCode, isWrapperError, arginfo_class_StreamErrorCode_isWrapperError, ZEND_ACC_PUBLIC) - ZEND_ME(StreamErrorCode, isFilterError, arginfo_class_StreamErrorCode_isFilterError, ZEND_ACC_PUBLIC) - ZEND_ME(StreamErrorCode, isCastError, arginfo_class_StreamErrorCode_isCastError, ZEND_ACC_PUBLIC) - ZEND_ME(StreamErrorCode, isNetworkError, arginfo_class_StreamErrorCode_isNetworkError, ZEND_ACC_PUBLIC) - ZEND_ME(StreamErrorCode, isEncodingError, arginfo_class_StreamErrorCode_isEncodingError, ZEND_ACC_PUBLIC) - ZEND_ME(StreamErrorCode, isResourceError, arginfo_class_StreamErrorCode_isResourceError, ZEND_ACC_PUBLIC) - ZEND_ME(StreamErrorCode, isLockError, arginfo_class_StreamErrorCode_isLockError, ZEND_ACC_PUBLIC) - ZEND_ME(StreamErrorCode, isUserspaceError, arginfo_class_StreamErrorCode_isUserspaceError, ZEND_ACC_PUBLIC) - ZEND_FE_END -}; - static const zend_function_entry class_StreamError_methods[] = { + ZEND_ME(StreamError, isIoError, arginfo_class_StreamError_isIoError, ZEND_ACC_PUBLIC) + ZEND_ME(StreamError, isFileSystemError, arginfo_class_StreamError_isFileSystemError, ZEND_ACC_PUBLIC) + ZEND_ME(StreamError, isWrapperError, arginfo_class_StreamError_isWrapperError, ZEND_ACC_PUBLIC) + ZEND_ME(StreamError, isFilterError, arginfo_class_StreamError_isFilterError, ZEND_ACC_PUBLIC) + ZEND_ME(StreamError, isCastError, arginfo_class_StreamError_isCastError, ZEND_ACC_PUBLIC) + ZEND_ME(StreamError, isNetworkError, arginfo_class_StreamError_isNetworkError, ZEND_ACC_PUBLIC) + ZEND_ME(StreamError, isEncodingError, arginfo_class_StreamError_isEncodingError, ZEND_ACC_PUBLIC) + ZEND_ME(StreamError, isResourceError, arginfo_class_StreamError_isResourceError, ZEND_ACC_PUBLIC) + ZEND_ME(StreamError, isLockError, arginfo_class_StreamError_isLockError, ZEND_ACC_PUBLIC) + ZEND_ME(StreamError, isUserspaceError, arginfo_class_StreamError_isUserspaceError, ZEND_ACC_PUBLIC) ZEND_ME(StreamError, hasCode, arginfo_class_StreamError_hasCode, ZEND_ACC_PUBLIC) ZEND_ME(StreamError, count, arginfo_class_StreamError_count, ZEND_ACC_PUBLIC) ZEND_FE_END @@ -71,13 +67,6 @@ static const zend_function_entry class_StreamException_methods[] = { ZEND_FE_END }; -static zend_class_entry *register_class_StreamErrorCode(void) -{ - zend_class_entry *class_entry = zend_register_internal_enum("StreamErrorCode", IS_LONG, class_StreamErrorCode_methods); - - return class_entry; -} - static zend_class_entry *register_class_StreamErrorMode(void) { zend_class_entry *class_entry = zend_register_internal_enum("StreamErrorMode", IS_UNDEF, NULL); @@ -115,10 +104,465 @@ static zend_class_entry *register_class_StreamError(void) INIT_CLASS_ENTRY(ce, "StreamError", class_StreamError_methods); class_entry = zend_register_internal_class_with_flags(&ce, NULL, ZEND_ACC_FINAL|ZEND_ACC_READONLY_CLASS); + zval const_CODE_NONE_value; + ZVAL_LONG(&const_CODE_NONE_value, STREAM_ERROR_CODE_NONE); + zend_string *const_CODE_NONE_name = zend_string_init_interned("CODE_NONE", sizeof("CODE_NONE") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_NONE_name, &const_CODE_NONE_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_NONE_name, true); + + zval const_CODE_GENERIC_value; + ZVAL_LONG(&const_CODE_GENERIC_value, STREAM_ERROR_CODE_GENERIC); + zend_string *const_CODE_GENERIC_name = zend_string_init_interned("CODE_GENERIC", sizeof("CODE_GENERIC") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_GENERIC_name, &const_CODE_GENERIC_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_GENERIC_name, true); + + zval const_CODE_READ_FAILED_value; + ZVAL_LONG(&const_CODE_READ_FAILED_value, STREAM_ERROR_CODE_READ_FAILED); + zend_string *const_CODE_READ_FAILED_name = zend_string_init_interned("CODE_READ_FAILED", sizeof("CODE_READ_FAILED") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_READ_FAILED_name, &const_CODE_READ_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_READ_FAILED_name, true); + + zval const_CODE_WRITE_FAILED_value; + ZVAL_LONG(&const_CODE_WRITE_FAILED_value, STREAM_ERROR_CODE_WRITE_FAILED); + zend_string *const_CODE_WRITE_FAILED_name = zend_string_init_interned("CODE_WRITE_FAILED", sizeof("CODE_WRITE_FAILED") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_WRITE_FAILED_name, &const_CODE_WRITE_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_WRITE_FAILED_name, true); + + zval const_CODE_SEEK_FAILED_value; + ZVAL_LONG(&const_CODE_SEEK_FAILED_value, STREAM_ERROR_CODE_SEEK_FAILED); + zend_string *const_CODE_SEEK_FAILED_name = zend_string_init_interned("CODE_SEEK_FAILED", sizeof("CODE_SEEK_FAILED") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_SEEK_FAILED_name, &const_CODE_SEEK_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_SEEK_FAILED_name, true); + + zval const_CODE_SEEK_NOT_SUPPORTED_value; + ZVAL_LONG(&const_CODE_SEEK_NOT_SUPPORTED_value, STREAM_ERROR_CODE_SEEK_NOT_SUPPORTED); + zend_string *const_CODE_SEEK_NOT_SUPPORTED_name = zend_string_init_interned("CODE_SEEK_NOT_SUPPORTED", sizeof("CODE_SEEK_NOT_SUPPORTED") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_SEEK_NOT_SUPPORTED_name, &const_CODE_SEEK_NOT_SUPPORTED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_SEEK_NOT_SUPPORTED_name, true); + + zval const_CODE_FLUSH_FAILED_value; + ZVAL_LONG(&const_CODE_FLUSH_FAILED_value, STREAM_ERROR_CODE_FLUSH_FAILED); + zend_string *const_CODE_FLUSH_FAILED_name = zend_string_init_interned("CODE_FLUSH_FAILED", sizeof("CODE_FLUSH_FAILED") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_FLUSH_FAILED_name, &const_CODE_FLUSH_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_FLUSH_FAILED_name, true); + + zval const_CODE_TRUNCATE_FAILED_value; + ZVAL_LONG(&const_CODE_TRUNCATE_FAILED_value, STREAM_ERROR_CODE_TRUNCATE_FAILED); + zend_string *const_CODE_TRUNCATE_FAILED_name = zend_string_init_interned("CODE_TRUNCATE_FAILED", sizeof("CODE_TRUNCATE_FAILED") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_TRUNCATE_FAILED_name, &const_CODE_TRUNCATE_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_TRUNCATE_FAILED_name, true); + + zval const_CODE_CONNECT_FAILED_value; + ZVAL_LONG(&const_CODE_CONNECT_FAILED_value, STREAM_ERROR_CODE_CONNECT_FAILED); + zend_string *const_CODE_CONNECT_FAILED_name = zend_string_init_interned("CODE_CONNECT_FAILED", sizeof("CODE_CONNECT_FAILED") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_CONNECT_FAILED_name, &const_CODE_CONNECT_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_CONNECT_FAILED_name, true); + + zval const_CODE_BIND_FAILED_value; + ZVAL_LONG(&const_CODE_BIND_FAILED_value, STREAM_ERROR_CODE_BIND_FAILED); + zend_string *const_CODE_BIND_FAILED_name = zend_string_init_interned("CODE_BIND_FAILED", sizeof("CODE_BIND_FAILED") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_BIND_FAILED_name, &const_CODE_BIND_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_BIND_FAILED_name, true); + + zval const_CODE_LISTEN_FAILED_value; + ZVAL_LONG(&const_CODE_LISTEN_FAILED_value, STREAM_ERROR_CODE_LISTEN_FAILED); + zend_string *const_CODE_LISTEN_FAILED_name = zend_string_init_interned("CODE_LISTEN_FAILED", sizeof("CODE_LISTEN_FAILED") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_LISTEN_FAILED_name, &const_CODE_LISTEN_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_LISTEN_FAILED_name, true); + + zval const_CODE_NOT_WRITABLE_value; + ZVAL_LONG(&const_CODE_NOT_WRITABLE_value, STREAM_ERROR_CODE_NOT_WRITABLE); + zend_string *const_CODE_NOT_WRITABLE_name = zend_string_init_interned("CODE_NOT_WRITABLE", sizeof("CODE_NOT_WRITABLE") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_NOT_WRITABLE_name, &const_CODE_NOT_WRITABLE_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_NOT_WRITABLE_name, true); + + zval const_CODE_NOT_READABLE_value; + ZVAL_LONG(&const_CODE_NOT_READABLE_value, STREAM_ERROR_CODE_NOT_READABLE); + zend_string *const_CODE_NOT_READABLE_name = zend_string_init_interned("CODE_NOT_READABLE", sizeof("CODE_NOT_READABLE") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_NOT_READABLE_name, &const_CODE_NOT_READABLE_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_NOT_READABLE_name, true); + + zval const_CODE_DISABLED_value; + ZVAL_LONG(&const_CODE_DISABLED_value, STREAM_ERROR_CODE_DISABLED); + zend_string *const_CODE_DISABLED_name = zend_string_init_interned("CODE_DISABLED", sizeof("CODE_DISABLED") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_DISABLED_name, &const_CODE_DISABLED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_DISABLED_name, true); + + zval const_CODE_NOT_FOUND_value; + ZVAL_LONG(&const_CODE_NOT_FOUND_value, STREAM_ERROR_CODE_NOT_FOUND); + zend_string *const_CODE_NOT_FOUND_name = zend_string_init_interned("CODE_NOT_FOUND", sizeof("CODE_NOT_FOUND") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_NOT_FOUND_name, &const_CODE_NOT_FOUND_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_NOT_FOUND_name, true); + + zval const_CODE_PERMISSION_DENIED_value; + ZVAL_LONG(&const_CODE_PERMISSION_DENIED_value, STREAM_ERROR_CODE_PERMISSION_DENIED); + zend_string *const_CODE_PERMISSION_DENIED_name = zend_string_init_interned("CODE_PERMISSION_DENIED", sizeof("CODE_PERMISSION_DENIED") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_PERMISSION_DENIED_name, &const_CODE_PERMISSION_DENIED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_PERMISSION_DENIED_name, true); + + zval const_CODE_ALREADY_EXISTS_value; + ZVAL_LONG(&const_CODE_ALREADY_EXISTS_value, STREAM_ERROR_CODE_ALREADY_EXISTS); + zend_string *const_CODE_ALREADY_EXISTS_name = zend_string_init_interned("CODE_ALREADY_EXISTS", sizeof("CODE_ALREADY_EXISTS") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_ALREADY_EXISTS_name, &const_CODE_ALREADY_EXISTS_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_ALREADY_EXISTS_name, true); + + zval const_CODE_INVALID_PATH_value; + ZVAL_LONG(&const_CODE_INVALID_PATH_value, STREAM_ERROR_CODE_INVALID_PATH); + zend_string *const_CODE_INVALID_PATH_name = zend_string_init_interned("CODE_INVALID_PATH", sizeof("CODE_INVALID_PATH") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_INVALID_PATH_name, &const_CODE_INVALID_PATH_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_INVALID_PATH_name, true); + + zval const_CODE_PATH_TOO_LONG_value; + ZVAL_LONG(&const_CODE_PATH_TOO_LONG_value, STREAM_ERROR_CODE_PATH_TOO_LONG); + zend_string *const_CODE_PATH_TOO_LONG_name = zend_string_init_interned("CODE_PATH_TOO_LONG", sizeof("CODE_PATH_TOO_LONG") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_PATH_TOO_LONG_name, &const_CODE_PATH_TOO_LONG_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_PATH_TOO_LONG_name, true); + + zval const_CODE_OPEN_FAILED_value; + ZVAL_LONG(&const_CODE_OPEN_FAILED_value, STREAM_ERROR_CODE_OPEN_FAILED); + zend_string *const_CODE_OPEN_FAILED_name = zend_string_init_interned("CODE_OPEN_FAILED", sizeof("CODE_OPEN_FAILED") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_OPEN_FAILED_name, &const_CODE_OPEN_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_OPEN_FAILED_name, true); + + zval const_CODE_CREATE_FAILED_value; + ZVAL_LONG(&const_CODE_CREATE_FAILED_value, STREAM_ERROR_CODE_CREATE_FAILED); + zend_string *const_CODE_CREATE_FAILED_name = zend_string_init_interned("CODE_CREATE_FAILED", sizeof("CODE_CREATE_FAILED") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_CREATE_FAILED_name, &const_CODE_CREATE_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_CREATE_FAILED_name, true); + + zval const_CODE_DUP_FAILED_value; + ZVAL_LONG(&const_CODE_DUP_FAILED_value, STREAM_ERROR_CODE_DUP_FAILED); + zend_string *const_CODE_DUP_FAILED_name = zend_string_init_interned("CODE_DUP_FAILED", sizeof("CODE_DUP_FAILED") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_DUP_FAILED_name, &const_CODE_DUP_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_DUP_FAILED_name, true); + + zval const_CODE_UNLINK_FAILED_value; + ZVAL_LONG(&const_CODE_UNLINK_FAILED_value, STREAM_ERROR_CODE_UNLINK_FAILED); + zend_string *const_CODE_UNLINK_FAILED_name = zend_string_init_interned("CODE_UNLINK_FAILED", sizeof("CODE_UNLINK_FAILED") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_UNLINK_FAILED_name, &const_CODE_UNLINK_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_UNLINK_FAILED_name, true); + + zval const_CODE_RENAME_FAILED_value; + ZVAL_LONG(&const_CODE_RENAME_FAILED_value, STREAM_ERROR_CODE_RENAME_FAILED); + zend_string *const_CODE_RENAME_FAILED_name = zend_string_init_interned("CODE_RENAME_FAILED", sizeof("CODE_RENAME_FAILED") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_RENAME_FAILED_name, &const_CODE_RENAME_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_RENAME_FAILED_name, true); + + zval const_CODE_MKDIR_FAILED_value; + ZVAL_LONG(&const_CODE_MKDIR_FAILED_value, STREAM_ERROR_CODE_MKDIR_FAILED); + zend_string *const_CODE_MKDIR_FAILED_name = zend_string_init_interned("CODE_MKDIR_FAILED", sizeof("CODE_MKDIR_FAILED") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_MKDIR_FAILED_name, &const_CODE_MKDIR_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_MKDIR_FAILED_name, true); + + zval const_CODE_RMDIR_FAILED_value; + ZVAL_LONG(&const_CODE_RMDIR_FAILED_value, STREAM_ERROR_CODE_RMDIR_FAILED); + zend_string *const_CODE_RMDIR_FAILED_name = zend_string_init_interned("CODE_RMDIR_FAILED", sizeof("CODE_RMDIR_FAILED") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_RMDIR_FAILED_name, &const_CODE_RMDIR_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_RMDIR_FAILED_name, true); + + zval const_CODE_STAT_FAILED_value; + ZVAL_LONG(&const_CODE_STAT_FAILED_value, STREAM_ERROR_CODE_STAT_FAILED); + zend_string *const_CODE_STAT_FAILED_name = zend_string_init_interned("CODE_STAT_FAILED", sizeof("CODE_STAT_FAILED") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_STAT_FAILED_name, &const_CODE_STAT_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_STAT_FAILED_name, true); + + zval const_CODE_META_FAILED_value; + ZVAL_LONG(&const_CODE_META_FAILED_value, STREAM_ERROR_CODE_META_FAILED); + zend_string *const_CODE_META_FAILED_name = zend_string_init_interned("CODE_META_FAILED", sizeof("CODE_META_FAILED") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_META_FAILED_name, &const_CODE_META_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_META_FAILED_name, true); + + zval const_CODE_CHMOD_FAILED_value; + ZVAL_LONG(&const_CODE_CHMOD_FAILED_value, STREAM_ERROR_CODE_CHMOD_FAILED); + zend_string *const_CODE_CHMOD_FAILED_name = zend_string_init_interned("CODE_CHMOD_FAILED", sizeof("CODE_CHMOD_FAILED") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_CHMOD_FAILED_name, &const_CODE_CHMOD_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_CHMOD_FAILED_name, true); + + zval const_CODE_CHOWN_FAILED_value; + ZVAL_LONG(&const_CODE_CHOWN_FAILED_value, STREAM_ERROR_CODE_CHOWN_FAILED); + zend_string *const_CODE_CHOWN_FAILED_name = zend_string_init_interned("CODE_CHOWN_FAILED", sizeof("CODE_CHOWN_FAILED") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_CHOWN_FAILED_name, &const_CODE_CHOWN_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_CHOWN_FAILED_name, true); + + zval const_CODE_COPY_FAILED_value; + ZVAL_LONG(&const_CODE_COPY_FAILED_value, STREAM_ERROR_CODE_COPY_FAILED); + zend_string *const_CODE_COPY_FAILED_name = zend_string_init_interned("CODE_COPY_FAILED", sizeof("CODE_COPY_FAILED") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_COPY_FAILED_name, &const_CODE_COPY_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_COPY_FAILED_name, true); + + zval const_CODE_TOUCH_FAILED_value; + ZVAL_LONG(&const_CODE_TOUCH_FAILED_value, STREAM_ERROR_CODE_TOUCH_FAILED); + zend_string *const_CODE_TOUCH_FAILED_name = zend_string_init_interned("CODE_TOUCH_FAILED", sizeof("CODE_TOUCH_FAILED") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_TOUCH_FAILED_name, &const_CODE_TOUCH_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_TOUCH_FAILED_name, true); + + zval const_CODE_INVALID_MODE_value; + ZVAL_LONG(&const_CODE_INVALID_MODE_value, STREAM_ERROR_CODE_INVALID_MODE); + zend_string *const_CODE_INVALID_MODE_name = zend_string_init_interned("CODE_INVALID_MODE", sizeof("CODE_INVALID_MODE") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_INVALID_MODE_name, &const_CODE_INVALID_MODE_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_INVALID_MODE_name, true); + + zval const_CODE_INVALID_META_value; + ZVAL_LONG(&const_CODE_INVALID_META_value, STREAM_ERROR_CODE_INVALID_META); + zend_string *const_CODE_INVALID_META_name = zend_string_init_interned("CODE_INVALID_META", sizeof("CODE_INVALID_META") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_INVALID_META_name, &const_CODE_INVALID_META_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_INVALID_META_name, true); + + zval const_CODE_MODE_NOT_SUPPORTED_value; + ZVAL_LONG(&const_CODE_MODE_NOT_SUPPORTED_value, STREAM_ERROR_CODE_MODE_NOT_SUPPORTED); + zend_string *const_CODE_MODE_NOT_SUPPORTED_name = zend_string_init_interned("CODE_MODE_NOT_SUPPORTED", sizeof("CODE_MODE_NOT_SUPPORTED") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_MODE_NOT_SUPPORTED_name, &const_CODE_MODE_NOT_SUPPORTED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_MODE_NOT_SUPPORTED_name, true); + + zval const_CODE_READONLY_value; + ZVAL_LONG(&const_CODE_READONLY_value, STREAM_ERROR_CODE_READONLY); + zend_string *const_CODE_READONLY_name = zend_string_init_interned("CODE_READONLY", sizeof("CODE_READONLY") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_READONLY_name, &const_CODE_READONLY_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_READONLY_name, true); + + zval const_CODE_RECURSION_DETECTED_value; + ZVAL_LONG(&const_CODE_RECURSION_DETECTED_value, STREAM_ERROR_CODE_RECURSION_DETECTED); + zend_string *const_CODE_RECURSION_DETECTED_name = zend_string_init_interned("CODE_RECURSION_DETECTED", sizeof("CODE_RECURSION_DETECTED") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_RECURSION_DETECTED_name, &const_CODE_RECURSION_DETECTED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_RECURSION_DETECTED_name, true); + + zval const_CODE_NOT_IMPLEMENTED_value; + ZVAL_LONG(&const_CODE_NOT_IMPLEMENTED_value, STREAM_ERROR_CODE_NOT_IMPLEMENTED); + zend_string *const_CODE_NOT_IMPLEMENTED_name = zend_string_init_interned("CODE_NOT_IMPLEMENTED", sizeof("CODE_NOT_IMPLEMENTED") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_NOT_IMPLEMENTED_name, &const_CODE_NOT_IMPLEMENTED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_NOT_IMPLEMENTED_name, true); + + zval const_CODE_NO_OPENER_value; + ZVAL_LONG(&const_CODE_NO_OPENER_value, STREAM_ERROR_CODE_NO_OPENER); + zend_string *const_CODE_NO_OPENER_name = zend_string_init_interned("CODE_NO_OPENER", sizeof("CODE_NO_OPENER") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_NO_OPENER_name, &const_CODE_NO_OPENER_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_NO_OPENER_name, true); + + zval const_CODE_PERSISTENT_NOT_SUPPORTED_value; + ZVAL_LONG(&const_CODE_PERSISTENT_NOT_SUPPORTED_value, STREAM_ERROR_CODE_PERSISTENT_NOT_SUPPORTED); + zend_string *const_CODE_PERSISTENT_NOT_SUPPORTED_name = zend_string_init_interned("CODE_PERSISTENT_NOT_SUPPORTED", sizeof("CODE_PERSISTENT_NOT_SUPPORTED") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_PERSISTENT_NOT_SUPPORTED_name, &const_CODE_PERSISTENT_NOT_SUPPORTED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_PERSISTENT_NOT_SUPPORTED_name, true); + + zval const_CODE_WRAPPER_NOT_FOUND_value; + ZVAL_LONG(&const_CODE_WRAPPER_NOT_FOUND_value, STREAM_ERROR_CODE_WRAPPER_NOT_FOUND); + zend_string *const_CODE_WRAPPER_NOT_FOUND_name = zend_string_init_interned("CODE_WRAPPER_NOT_FOUND", sizeof("CODE_WRAPPER_NOT_FOUND") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_WRAPPER_NOT_FOUND_name, &const_CODE_WRAPPER_NOT_FOUND_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_WRAPPER_NOT_FOUND_name, true); + + zval const_CODE_WRAPPER_DISABLED_value; + ZVAL_LONG(&const_CODE_WRAPPER_DISABLED_value, STREAM_ERROR_CODE_WRAPPER_DISABLED); + zend_string *const_CODE_WRAPPER_DISABLED_name = zend_string_init_interned("CODE_WRAPPER_DISABLED", sizeof("CODE_WRAPPER_DISABLED") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_WRAPPER_DISABLED_name, &const_CODE_WRAPPER_DISABLED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_WRAPPER_DISABLED_name, true); + + zval const_CODE_PROTOCOL_UNSUPPORTED_value; + ZVAL_LONG(&const_CODE_PROTOCOL_UNSUPPORTED_value, STREAM_ERROR_CODE_PROTOCOL_UNSUPPORTED); + zend_string *const_CODE_PROTOCOL_UNSUPPORTED_name = zend_string_init_interned("CODE_PROTOCOL_UNSUPPORTED", sizeof("CODE_PROTOCOL_UNSUPPORTED") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_PROTOCOL_UNSUPPORTED_name, &const_CODE_PROTOCOL_UNSUPPORTED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_PROTOCOL_UNSUPPORTED_name, true); + + zval const_CODE_WRAPPER_REGISTRATION_FAILED_value; + ZVAL_LONG(&const_CODE_WRAPPER_REGISTRATION_FAILED_value, STREAM_ERROR_CODE_WRAPPER_REGISTRATION_FAILED); + zend_string *const_CODE_WRAPPER_REGISTRATION_FAILED_name = zend_string_init_interned("CODE_WRAPPER_REGISTRATION_FAILED", sizeof("CODE_WRAPPER_REGISTRATION_FAILED") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_WRAPPER_REGISTRATION_FAILED_name, &const_CODE_WRAPPER_REGISTRATION_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_WRAPPER_REGISTRATION_FAILED_name, true); + + zval const_CODE_WRAPPER_UNREGISTRATION_FAILED_value; + ZVAL_LONG(&const_CODE_WRAPPER_UNREGISTRATION_FAILED_value, STREAM_ERROR_CODE_WRAPPER_UNREGISTRATION_FAILED); + zend_string *const_CODE_WRAPPER_UNREGISTRATION_FAILED_name = zend_string_init_interned("CODE_WRAPPER_UNREGISTRATION_FAILED", sizeof("CODE_WRAPPER_UNREGISTRATION_FAILED") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_WRAPPER_UNREGISTRATION_FAILED_name, &const_CODE_WRAPPER_UNREGISTRATION_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_WRAPPER_UNREGISTRATION_FAILED_name, true); + + zval const_CODE_WRAPPER_RESTORATION_FAILED_value; + ZVAL_LONG(&const_CODE_WRAPPER_RESTORATION_FAILED_value, STREAM_ERROR_CODE_WRAPPER_RESTORATION_FAILED); + zend_string *const_CODE_WRAPPER_RESTORATION_FAILED_name = zend_string_init_interned("CODE_WRAPPER_RESTORATION_FAILED", sizeof("CODE_WRAPPER_RESTORATION_FAILED") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_WRAPPER_RESTORATION_FAILED_name, &const_CODE_WRAPPER_RESTORATION_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_WRAPPER_RESTORATION_FAILED_name, true); + + zval const_CODE_FILTER_NOT_FOUND_value; + ZVAL_LONG(&const_CODE_FILTER_NOT_FOUND_value, STREAM_ERROR_CODE_FILTER_NOT_FOUND); + zend_string *const_CODE_FILTER_NOT_FOUND_name = zend_string_init_interned("CODE_FILTER_NOT_FOUND", sizeof("CODE_FILTER_NOT_FOUND") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_FILTER_NOT_FOUND_name, &const_CODE_FILTER_NOT_FOUND_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_FILTER_NOT_FOUND_name, true); + + zval const_CODE_FILTER_FAILED_value; + ZVAL_LONG(&const_CODE_FILTER_FAILED_value, STREAM_ERROR_CODE_FILTER_FAILED); + zend_string *const_CODE_FILTER_FAILED_name = zend_string_init_interned("CODE_FILTER_FAILED", sizeof("CODE_FILTER_FAILED") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_FILTER_FAILED_name, &const_CODE_FILTER_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_FILTER_FAILED_name, true); + + zval const_CODE_CAST_FAILED_value; + ZVAL_LONG(&const_CODE_CAST_FAILED_value, STREAM_ERROR_CODE_CAST_FAILED); + zend_string *const_CODE_CAST_FAILED_name = zend_string_init_interned("CODE_CAST_FAILED", sizeof("CODE_CAST_FAILED") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_CAST_FAILED_name, &const_CODE_CAST_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_CAST_FAILED_name, true); + + zval const_CODE_CAST_NOT_SUPPORTED_value; + ZVAL_LONG(&const_CODE_CAST_NOT_SUPPORTED_value, STREAM_ERROR_CODE_CAST_NOT_SUPPORTED); + zend_string *const_CODE_CAST_NOT_SUPPORTED_name = zend_string_init_interned("CODE_CAST_NOT_SUPPORTED", sizeof("CODE_CAST_NOT_SUPPORTED") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_CAST_NOT_SUPPORTED_name, &const_CODE_CAST_NOT_SUPPORTED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_CAST_NOT_SUPPORTED_name, true); + + zval const_CODE_MAKE_SEEKABLE_FAILED_value; + ZVAL_LONG(&const_CODE_MAKE_SEEKABLE_FAILED_value, STREAM_ERROR_CODE_MAKE_SEEKABLE_FAILED); + zend_string *const_CODE_MAKE_SEEKABLE_FAILED_name = zend_string_init_interned("CODE_MAKE_SEEKABLE_FAILED", sizeof("CODE_MAKE_SEEKABLE_FAILED") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_MAKE_SEEKABLE_FAILED_name, &const_CODE_MAKE_SEEKABLE_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_MAKE_SEEKABLE_FAILED_name, true); + + zval const_CODE_BUFFERED_DATA_LOST_value; + ZVAL_LONG(&const_CODE_BUFFERED_DATA_LOST_value, STREAM_ERROR_CODE_BUFFERED_DATA_LOST); + zend_string *const_CODE_BUFFERED_DATA_LOST_name = zend_string_init_interned("CODE_BUFFERED_DATA_LOST", sizeof("CODE_BUFFERED_DATA_LOST") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_BUFFERED_DATA_LOST_name, &const_CODE_BUFFERED_DATA_LOST_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_BUFFERED_DATA_LOST_name, true); + + zval const_CODE_NETWORK_SEND_FAILED_value; + ZVAL_LONG(&const_CODE_NETWORK_SEND_FAILED_value, STREAM_ERROR_CODE_NETWORK_SEND_FAILED); + zend_string *const_CODE_NETWORK_SEND_FAILED_name = zend_string_init_interned("CODE_NETWORK_SEND_FAILED", sizeof("CODE_NETWORK_SEND_FAILED") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_NETWORK_SEND_FAILED_name, &const_CODE_NETWORK_SEND_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_NETWORK_SEND_FAILED_name, true); + + zval const_CODE_NETWORK_RECV_FAILED_value; + ZVAL_LONG(&const_CODE_NETWORK_RECV_FAILED_value, STREAM_ERROR_CODE_NETWORK_RECV_FAILED); + zend_string *const_CODE_NETWORK_RECV_FAILED_name = zend_string_init_interned("CODE_NETWORK_RECV_FAILED", sizeof("CODE_NETWORK_RECV_FAILED") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_NETWORK_RECV_FAILED_name, &const_CODE_NETWORK_RECV_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_NETWORK_RECV_FAILED_name, true); + + zval const_CODE_SSL_NOT_SUPPORTED_value; + ZVAL_LONG(&const_CODE_SSL_NOT_SUPPORTED_value, STREAM_ERROR_CODE_SSL_NOT_SUPPORTED); + zend_string *const_CODE_SSL_NOT_SUPPORTED_name = zend_string_init_interned("CODE_SSL_NOT_SUPPORTED", sizeof("CODE_SSL_NOT_SUPPORTED") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_SSL_NOT_SUPPORTED_name, &const_CODE_SSL_NOT_SUPPORTED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_SSL_NOT_SUPPORTED_name, true); + + zval const_CODE_RESUMPTION_FAILED_value; + ZVAL_LONG(&const_CODE_RESUMPTION_FAILED_value, STREAM_ERROR_CODE_RESUMPTION_FAILED); + zend_string *const_CODE_RESUMPTION_FAILED_name = zend_string_init_interned("CODE_RESUMPTION_FAILED", sizeof("CODE_RESUMPTION_FAILED") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_RESUMPTION_FAILED_name, &const_CODE_RESUMPTION_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_RESUMPTION_FAILED_name, true); + + zval const_CODE_SOCKET_PATH_TOO_LONG_value; + ZVAL_LONG(&const_CODE_SOCKET_PATH_TOO_LONG_value, STREAM_ERROR_CODE_SOCKET_PATH_TOO_LONG); + zend_string *const_CODE_SOCKET_PATH_TOO_LONG_name = zend_string_init_interned("CODE_SOCKET_PATH_TOO_LONG", sizeof("CODE_SOCKET_PATH_TOO_LONG") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_SOCKET_PATH_TOO_LONG_name, &const_CODE_SOCKET_PATH_TOO_LONG_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_SOCKET_PATH_TOO_LONG_name, true); + + zval const_CODE_OOB_NOT_SUPPORTED_value; + ZVAL_LONG(&const_CODE_OOB_NOT_SUPPORTED_value, STREAM_ERROR_CODE_OOB_NOT_SUPPORTED); + zend_string *const_CODE_OOB_NOT_SUPPORTED_name = zend_string_init_interned("CODE_OOB_NOT_SUPPORTED", sizeof("CODE_OOB_NOT_SUPPORTED") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_OOB_NOT_SUPPORTED_name, &const_CODE_OOB_NOT_SUPPORTED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_OOB_NOT_SUPPORTED_name, true); + + zval const_CODE_PROTOCOL_ERROR_value; + ZVAL_LONG(&const_CODE_PROTOCOL_ERROR_value, STREAM_ERROR_CODE_PROTOCOL_ERROR); + zend_string *const_CODE_PROTOCOL_ERROR_name = zend_string_init_interned("CODE_PROTOCOL_ERROR", sizeof("CODE_PROTOCOL_ERROR") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_PROTOCOL_ERROR_name, &const_CODE_PROTOCOL_ERROR_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_PROTOCOL_ERROR_name, true); + + zval const_CODE_INVALID_URL_value; + ZVAL_LONG(&const_CODE_INVALID_URL_value, STREAM_ERROR_CODE_INVALID_URL); + zend_string *const_CODE_INVALID_URL_name = zend_string_init_interned("CODE_INVALID_URL", sizeof("CODE_INVALID_URL") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_INVALID_URL_name, &const_CODE_INVALID_URL_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_INVALID_URL_name, true); + + zval const_CODE_INVALID_RESPONSE_value; + ZVAL_LONG(&const_CODE_INVALID_RESPONSE_value, STREAM_ERROR_CODE_INVALID_RESPONSE); + zend_string *const_CODE_INVALID_RESPONSE_name = zend_string_init_interned("CODE_INVALID_RESPONSE", sizeof("CODE_INVALID_RESPONSE") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_INVALID_RESPONSE_name, &const_CODE_INVALID_RESPONSE_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_INVALID_RESPONSE_name, true); + + zval const_CODE_INVALID_HEADER_value; + ZVAL_LONG(&const_CODE_INVALID_HEADER_value, STREAM_ERROR_CODE_INVALID_HEADER); + zend_string *const_CODE_INVALID_HEADER_name = zend_string_init_interned("CODE_INVALID_HEADER", sizeof("CODE_INVALID_HEADER") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_INVALID_HEADER_name, &const_CODE_INVALID_HEADER_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_INVALID_HEADER_name, true); + + zval const_CODE_INVALID_PARAM_value; + ZVAL_LONG(&const_CODE_INVALID_PARAM_value, STREAM_ERROR_CODE_INVALID_PARAM); + zend_string *const_CODE_INVALID_PARAM_name = zend_string_init_interned("CODE_INVALID_PARAM", sizeof("CODE_INVALID_PARAM") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_INVALID_PARAM_name, &const_CODE_INVALID_PARAM_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_INVALID_PARAM_name, true); + + zval const_CODE_REDIRECT_LIMIT_value; + ZVAL_LONG(&const_CODE_REDIRECT_LIMIT_value, STREAM_ERROR_CODE_REDIRECT_LIMIT); + zend_string *const_CODE_REDIRECT_LIMIT_name = zend_string_init_interned("CODE_REDIRECT_LIMIT", sizeof("CODE_REDIRECT_LIMIT") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_REDIRECT_LIMIT_name, &const_CODE_REDIRECT_LIMIT_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_REDIRECT_LIMIT_name, true); + + zval const_CODE_AUTH_FAILED_value; + ZVAL_LONG(&const_CODE_AUTH_FAILED_value, STREAM_ERROR_CODE_AUTH_FAILED); + zend_string *const_CODE_AUTH_FAILED_name = zend_string_init_interned("CODE_AUTH_FAILED", sizeof("CODE_AUTH_FAILED") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_AUTH_FAILED_name, &const_CODE_AUTH_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_AUTH_FAILED_name, true); + + zval const_CODE_ARCHIVING_FAILED_value; + ZVAL_LONG(&const_CODE_ARCHIVING_FAILED_value, STREAM_ERROR_CODE_ARCHIVING_FAILED); + zend_string *const_CODE_ARCHIVING_FAILED_name = zend_string_init_interned("CODE_ARCHIVING_FAILED", sizeof("CODE_ARCHIVING_FAILED") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_ARCHIVING_FAILED_name, &const_CODE_ARCHIVING_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_ARCHIVING_FAILED_name, true); + + zval const_CODE_ENCODING_FAILED_value; + ZVAL_LONG(&const_CODE_ENCODING_FAILED_value, STREAM_ERROR_CODE_ENCODING_FAILED); + zend_string *const_CODE_ENCODING_FAILED_name = zend_string_init_interned("CODE_ENCODING_FAILED", sizeof("CODE_ENCODING_FAILED") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_ENCODING_FAILED_name, &const_CODE_ENCODING_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_ENCODING_FAILED_name, true); + + zval const_CODE_DECODING_FAILED_value; + ZVAL_LONG(&const_CODE_DECODING_FAILED_value, STREAM_ERROR_CODE_DECODING_FAILED); + zend_string *const_CODE_DECODING_FAILED_name = zend_string_init_interned("CODE_DECODING_FAILED", sizeof("CODE_DECODING_FAILED") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_DECODING_FAILED_name, &const_CODE_DECODING_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_DECODING_FAILED_name, true); + + zval const_CODE_INVALID_FORMAT_value; + ZVAL_LONG(&const_CODE_INVALID_FORMAT_value, STREAM_ERROR_CODE_INVALID_FORMAT); + zend_string *const_CODE_INVALID_FORMAT_name = zend_string_init_interned("CODE_INVALID_FORMAT", sizeof("CODE_INVALID_FORMAT") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_INVALID_FORMAT_name, &const_CODE_INVALID_FORMAT_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_INVALID_FORMAT_name, true); + + zval const_CODE_ALLOCATION_FAILED_value; + ZVAL_LONG(&const_CODE_ALLOCATION_FAILED_value, STREAM_ERROR_CODE_ALLOCATION_FAILED); + zend_string *const_CODE_ALLOCATION_FAILED_name = zend_string_init_interned("CODE_ALLOCATION_FAILED", sizeof("CODE_ALLOCATION_FAILED") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_ALLOCATION_FAILED_name, &const_CODE_ALLOCATION_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_ALLOCATION_FAILED_name, true); + + zval const_CODE_TEMPORARY_FILE_FAILED_value; + ZVAL_LONG(&const_CODE_TEMPORARY_FILE_FAILED_value, STREAM_ERROR_CODE_TEMPORARY_FILE_FAILED); + zend_string *const_CODE_TEMPORARY_FILE_FAILED_name = zend_string_init_interned("CODE_TEMPORARY_FILE_FAILED", sizeof("CODE_TEMPORARY_FILE_FAILED") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_TEMPORARY_FILE_FAILED_name, &const_CODE_TEMPORARY_FILE_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_TEMPORARY_FILE_FAILED_name, true); + + zval const_CODE_LOCK_FAILED_value; + ZVAL_LONG(&const_CODE_LOCK_FAILED_value, STREAM_ERROR_CODE_LOCK_FAILED); + zend_string *const_CODE_LOCK_FAILED_name = zend_string_init_interned("CODE_LOCK_FAILED", sizeof("CODE_LOCK_FAILED") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_LOCK_FAILED_name, &const_CODE_LOCK_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_LOCK_FAILED_name, true); + + zval const_CODE_LOCK_NOT_SUPPORTED_value; + ZVAL_LONG(&const_CODE_LOCK_NOT_SUPPORTED_value, STREAM_ERROR_CODE_LOCK_NOT_SUPPORTED); + zend_string *const_CODE_LOCK_NOT_SUPPORTED_name = zend_string_init_interned("CODE_LOCK_NOT_SUPPORTED", sizeof("CODE_LOCK_NOT_SUPPORTED") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_LOCK_NOT_SUPPORTED_name, &const_CODE_LOCK_NOT_SUPPORTED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_LOCK_NOT_SUPPORTED_name, true); + + zval const_CODE_USERSPACE_NOT_IMPLEMENTED_value; + ZVAL_LONG(&const_CODE_USERSPACE_NOT_IMPLEMENTED_value, STREAM_ERROR_CODE_USERSPACE_NOT_IMPLEMENTED); + zend_string *const_CODE_USERSPACE_NOT_IMPLEMENTED_name = zend_string_init_interned("CODE_USERSPACE_NOT_IMPLEMENTED", sizeof("CODE_USERSPACE_NOT_IMPLEMENTED") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_USERSPACE_NOT_IMPLEMENTED_name, &const_CODE_USERSPACE_NOT_IMPLEMENTED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_USERSPACE_NOT_IMPLEMENTED_name, true); + + zval const_CODE_USERSPACE_INVALID_RETURN_value; + ZVAL_LONG(&const_CODE_USERSPACE_INVALID_RETURN_value, STREAM_ERROR_CODE_USERSPACE_INVALID_RETURN); + zend_string *const_CODE_USERSPACE_INVALID_RETURN_name = zend_string_init_interned("CODE_USERSPACE_INVALID_RETURN", sizeof("CODE_USERSPACE_INVALID_RETURN") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_USERSPACE_INVALID_RETURN_name, &const_CODE_USERSPACE_INVALID_RETURN_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_USERSPACE_INVALID_RETURN_name, true); + + zval const_CODE_USERSPACE_CALL_FAILED_value; + ZVAL_LONG(&const_CODE_USERSPACE_CALL_FAILED_value, STREAM_ERROR_CODE_USERSPACE_CALL_FAILED); + zend_string *const_CODE_USERSPACE_CALL_FAILED_name = zend_string_init_interned("CODE_USERSPACE_CALL_FAILED", sizeof("CODE_USERSPACE_CALL_FAILED") - 1, true); + zend_declare_typed_class_constant(class_entry, const_CODE_USERSPACE_CALL_FAILED_name, &const_CODE_USERSPACE_CALL_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(const_CODE_USERSPACE_CALL_FAILED_name, true); + zval property_code_default_value; ZVAL_UNDEF(&property_code_default_value); - zend_string *property_code_class_StreamErrorCode = zend_string_init("StreamErrorCode", sizeof("StreamErrorCode")-1, 1); - zend_declare_typed_property(class_entry, ZSTR_KNOWN(ZEND_STR_CODE), &property_code_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_CLASS(property_code_class_StreamErrorCode, 0, 0)); + zend_declare_typed_property(class_entry, ZSTR_KNOWN(ZEND_STR_CODE), &property_code_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zval property_message_default_value; ZVAL_UNDEF(&property_message_default_value); From 95ac95a14ac4f95856afb7a588d95a7e5d8d5c7a Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Fri, 27 Feb 2026 22:54:02 +0100 Subject: [PATCH 63/68] stream: prohibit setting error mode in default context --- ext/standard/basic_functions.stub.php | 18 +++-- ext/standard/basic_functions_arginfo.h | 10 ++- ext/standard/basic_functions_decl.h | 8 +- ext/standard/streamsfuncs.c | 75 ++++++++++++++----- .../stream_errors_mix_modes_storage.phpt | 10 +-- ...ream_errors_set_default_context_error.phpt | 18 +++++ 6 files changed, 105 insertions(+), 34 deletions(-) create mode 100644 ext/standard/tests/streams/stream_errors_set_default_context_error.phpt diff --git a/ext/standard/basic_functions.stub.php b/ext/standard/basic_functions.stub.php index 0d9312b5d13c8..6ea9915bab0b3 100644 --- a/ext/standard/basic_functions.stub.php +++ b/ext/standard/basic_functions.stub.php @@ -3376,7 +3376,10 @@ function soundex(string $string): string {} /* streamsfuncs.c */ -function stream_select(?array &$read, ?array &$write, ?array &$except, ?int $seconds, ?int $microseconds = null): int|false {} +/** + * @param resource|null $context + */ +function stream_select(?array &$read, ?array &$write, ?array &$except, ?int $seconds, ?int $microseconds = null, $context = null): int|false {} /** * @return resource @@ -3479,17 +3482,19 @@ function stream_socket_shutdown($stream, int $mode): bool {} #ifdef HAVE_SOCKETPAIR /** + * @param resource|null $context * @return array|false * @refcount 1 */ -function stream_socket_pair(int $domain, int $type, int $protocol): array|false {} +function stream_socket_pair(int $domain, int $type, int $protocol, $context = null): array|false {} #endif /** * @param resource $from * @param resource $to + * @param resource|null $context */ -function stream_copy_to_stream($from, $to, ?int $length = null, int $offset = 0): int|false {} +function stream_copy_to_stream($from, $to, ?int $length = null, int $offset = 0, $context = null): int|false {} /** * @param resource $stream @@ -3560,8 +3565,11 @@ function stream_get_last_error(): ?StreamError {} */ function stream_get_transports(): array {} -/** @param resource|string $stream */ -function stream_is_local($stream): bool {} +/** + * @param resource|string $stream + * @param resource|null $context + */ +function stream_is_local($stream, $context = null): bool {} /** @param resource $stream */ function stream_isatty($stream): bool {} diff --git a/ext/standard/basic_functions_arginfo.h b/ext/standard/basic_functions_arginfo.h index 47eafbbd04101..9a1a6369c9966 100644 --- a/ext/standard/basic_functions_arginfo.h +++ b/ext/standard/basic_functions_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit basic_functions.stub.php instead. - * Stub hash: 49482b049ef53a19aef36947da4d3ce3aac50cdf + * Stub hash: 6afe0eea6b3b3190ae083bf03e99f2341147684e * Has decl header: yes */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_set_time_limit, 0, 1, _IS_BOOL, 0) @@ -1823,6 +1823,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_stream_select, 0, 4, MAY_BE_LONG ZEND_ARG_TYPE_INFO(1, except, IS_ARRAY, 1) ZEND_ARG_TYPE_INFO(0, seconds, IS_LONG, 1) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, microseconds, IS_LONG, 1, "null") + ZEND_ARG_INFO_WITH_DEFAULT_VALUE(0, context, "null") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_stream_context_create, 0, 0, 0) @@ -1937,6 +1938,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_stream_socket_pair, 0, 3, MAY_BE ZEND_ARG_TYPE_INFO(0, domain, IS_LONG, 0) ZEND_ARG_TYPE_INFO(0, type, IS_LONG, 0) ZEND_ARG_TYPE_INFO(0, protocol, IS_LONG, 0) + ZEND_ARG_INFO_WITH_DEFAULT_VALUE(0, context, "null") ZEND_END_ARG_INFO() #endif @@ -1945,6 +1947,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_stream_copy_to_stream, 0, 2, MAY ZEND_ARG_INFO(0, to) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, length, IS_LONG, 1, "null") ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, offset, IS_LONG, 0, "0") + ZEND_ARG_INFO_WITH_DEFAULT_VALUE(0, context, "null") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_stream_get_contents, 0, 1, MAY_BE_STRING|MAY_BE_FALSE) @@ -1992,7 +1995,10 @@ ZEND_END_ARG_INFO() #define arginfo_stream_get_transports arginfo_ob_list_handlers -#define arginfo_stream_is_local arginfo_rewind +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_stream_is_local, 0, 1, _IS_BOOL, 0) + ZEND_ARG_INFO(0, stream) + ZEND_ARG_INFO_WITH_DEFAULT_VALUE(0, context, "null") +ZEND_END_ARG_INFO() #define arginfo_stream_isatty arginfo_rewind diff --git a/ext/standard/basic_functions_decl.h b/ext/standard/basic_functions_decl.h index 32ef5e4e4b82c..7a036c2dca349 100644 --- a/ext/standard/basic_functions_decl.h +++ b/ext/standard/basic_functions_decl.h @@ -1,8 +1,8 @@ /* This is a generated file, edit basic_functions.stub.php instead. - * Stub hash: 49482b049ef53a19aef36947da4d3ce3aac50cdf */ + * Stub hash: 6afe0eea6b3b3190ae083bf03e99f2341147684e */ -#ifndef ZEND_BASIC_FUNCTIONS_DECL_49482b049ef53a19aef36947da4d3ce3aac50cdf_H -#define ZEND_BASIC_FUNCTIONS_DECL_49482b049ef53a19aef36947da4d3ce3aac50cdf_H +#ifndef ZEND_BASIC_FUNCTIONS_DECL_6afe0eea6b3b3190ae083bf03e99f2341147684e_H +#define ZEND_BASIC_FUNCTIONS_DECL_6afe0eea6b3b3190ae083bf03e99f2341147684e_H typedef enum zend_enum_RoundingMode { ZEND_ENUM_RoundingMode_HalfAwayFromZero = 1, @@ -15,4 +15,4 @@ typedef enum zend_enum_RoundingMode { ZEND_ENUM_RoundingMode_PositiveInfinity = 8, } zend_enum_RoundingMode; -#endif /* ZEND_BASIC_FUNCTIONS_DECL_49482b049ef53a19aef36947da4d3ce3aac50cdf_H */ +#endif /* ZEND_BASIC_FUNCTIONS_DECL_6afe0eea6b3b3190ae083bf03e99f2341147684e_H */ diff --git a/ext/standard/streamsfuncs.c b/ext/standard/streamsfuncs.c index 89995889f9647..e853e1938aebe 100644 --- a/ext/standard/streamsfuncs.c +++ b/ext/standard/streamsfuncs.c @@ -50,11 +50,15 @@ PHP_FUNCTION(stream_socket_pair) zend_long domain, type, protocol; php_stream *s1, *s2; php_socket_t pair[2]; + zval *zcontext = NULL; + php_stream_context *context = NULL; - ZEND_PARSE_PARAMETERS_START(3, 3) + ZEND_PARSE_PARAMETERS_START(3, 4) Z_PARAM_LONG(domain) Z_PARAM_LONG(type) Z_PARAM_LONG(protocol) + Z_PARAM_OPTIONAL + Z_PARAM_RESOURCE_OR_NULL(zcontext) ZEND_PARSE_PARAMETERS_END(); if (0 != socketpair((int)domain, (int)type, (int)protocol, pair)) { @@ -65,12 +69,13 @@ PHP_FUNCTION(stream_socket_pair) } php_stream_error_operation_begin(); + context = php_stream_context_from_zval(zcontext, 0); s1 = php_stream_sock_open_from_socket(pair[0], 0); if (s1 == NULL) { close(pair[0]); close(pair[1]); - php_stream_error_operation_end(NULL); + php_stream_error_operation_end(context); php_error_docref(NULL, E_WARNING, "Failed to open stream from socketpair"); RETURN_FALSE; } @@ -78,7 +83,7 @@ PHP_FUNCTION(stream_socket_pair) if (s2 == NULL) { php_stream_free(s1, PHP_STREAM_FREE_CLOSE); close(pair[1]); - php_stream_error_operation_end(NULL); + php_stream_error_operation_end(context); php_error_docref(NULL, E_WARNING, "Failed to open stream from socketpair"); RETURN_FALSE; } @@ -93,7 +98,7 @@ PHP_FUNCTION(stream_socket_pair) add_next_index_resource(return_value, s1->res); add_next_index_resource(return_value, s2->res); - php_stream_error_operation_end(NULL); + php_stream_error_operation_end(context); } /* }}} */ #endif @@ -506,13 +511,16 @@ PHP_FUNCTION(stream_copy_to_stream) zend_long maxlen, pos = 0; bool maxlen_is_null = 1; size_t len; + zval *zcontext = NULL; + php_stream_context *context = NULL; - ZEND_PARSE_PARAMETERS_START(2, 4) + ZEND_PARSE_PARAMETERS_START(2, 5) PHP_Z_PARAM_STREAM(src) PHP_Z_PARAM_STREAM(dest) Z_PARAM_OPTIONAL Z_PARAM_LONG_OR_NULL(maxlen, maxlen_is_null) Z_PARAM_LONG(pos) + Z_PARAM_RESOURCE_OR_NULL(zcontext) ZEND_PARSE_PARAMETERS_END(); if (maxlen_is_null) { @@ -520,9 +528,10 @@ PHP_FUNCTION(stream_copy_to_stream) } php_stream_error_operation_begin(); + context = php_stream_context_from_zval(zcontext, 0); if (pos > 0 && php_stream_seek(src, pos, SEEK_SET) < 0) { - php_stream_error_operation_end(NULL); + php_stream_error_operation_end(context); php_error_docref(NULL, E_WARNING, "Failed to seek to position " ZEND_LONG_FMT " in the stream", pos); RETURN_FALSE; } @@ -532,7 +541,7 @@ PHP_FUNCTION(stream_copy_to_stream) } else { RETVAL_LONG(len); } - php_stream_error_operation_end(NULL); + php_stream_error_operation_end(context); } /* }}} */ @@ -778,7 +787,7 @@ static int stream_array_emulate_read_fd_set(zval *stream_array) /* {{{ Runs the select() system call on the sets of streams with a timeout specified by tv_sec and tv_usec */ PHP_FUNCTION(stream_select) { - zval *r_array, *w_array, *e_array; + zval *r_array, *w_array, *e_array, *zcontext = NULL; struct timeval tv, *tv_p = NULL; fd_set rfds, wfds, efds; php_socket_t max_fd = 0; @@ -787,14 +796,16 @@ PHP_FUNCTION(stream_select) bool secnull; bool usecnull = 1; int set_count, max_set_count = 0; + php_stream_context *context = NULL; - ZEND_PARSE_PARAMETERS_START(4, 5) + ZEND_PARSE_PARAMETERS_START(4, 6) Z_PARAM_ARRAY_EX2(r_array, 1, 1, 0) Z_PARAM_ARRAY_EX2(w_array, 1, 1, 0) Z_PARAM_ARRAY_EX2(e_array, 1, 1, 0) Z_PARAM_LONG_OR_NULL(sec, secnull) Z_PARAM_OPTIONAL Z_PARAM_LONG_OR_NULL(usec, usecnull) + Z_PARAM_RESOURCE_OR_NULL(zcontext) ZEND_PARSE_PARAMETERS_END(); FD_ZERO(&rfds); @@ -802,6 +813,7 @@ PHP_FUNCTION(stream_select) FD_ZERO(&efds); php_stream_error_operation_begin(); + context = php_stream_context_from_zval(zcontext, 0); if (r_array != NULL) { set_count = stream_array_to_fd_set(Z_ARR_P(r_array), &rfds, &max_fd); @@ -825,7 +837,7 @@ PHP_FUNCTION(stream_select) } if (!sets) { - php_stream_error_operation_end(NULL); + php_stream_error_operation_end(context); zend_value_error("No stream arrays were passed"); RETURN_THROWS(); } @@ -836,7 +848,7 @@ PHP_FUNCTION(stream_select) if (secnull && !usecnull) { if (usec != 0) { - php_stream_error_operation_end(NULL); + php_stream_error_operation_end(context); zend_argument_value_error(5, "must be null when argument #4 ($seconds) is null"); RETURN_THROWS(); } @@ -845,11 +857,11 @@ PHP_FUNCTION(stream_select) /* If seconds is not set to null, build the timeval, else we wait indefinitely */ if (!secnull) { if (sec < 0) { - php_stream_error_operation_end(NULL); + php_stream_error_operation_end(context); zend_argument_value_error(4, "must be greater than or equal to 0"); RETURN_THROWS(); } else if (usec < 0) { - php_stream_error_operation_end(NULL); + php_stream_error_operation_end(context); zend_argument_value_error(5, "must be greater than or equal to 0"); RETURN_THROWS(); } @@ -866,7 +878,7 @@ PHP_FUNCTION(stream_select) if (r_array != NULL) { retval = stream_array_emulate_read_fd_set(r_array); if (retval > 0) { - php_stream_error_operation_end(NULL); + php_stream_error_operation_end(context); if (w_array != NULL) { zval_ptr_dtor(w_array); ZVAL_EMPTY_ARRAY(w_array); @@ -880,7 +892,7 @@ PHP_FUNCTION(stream_select) } retval = php_select(max_fd+1, &rfds, &wfds, &efds, tv_p); - php_stream_error_operation_end(NULL); + php_stream_error_operation_end(context); if (retval == -1) { php_error_docref(NULL, E_WARNING, "Unable to select [%d]: %s (max_fd=" PHP_SOCKET_FMT ")", @@ -1207,6 +1219,24 @@ PHP_FUNCTION(stream_context_get_default) } /* }}} */ +/* Check if options contain stream error handling settings */ +static bool php_stream_context_options_has_error_settings(const HashTable *options) +{ + zval *stream_options = zend_hash_str_find(options, ZEND_STRL("stream")); + if (!stream_options) { + return false; + } + + ZVAL_DEREF(stream_options); + if (Z_TYPE_P(stream_options) != IS_ARRAY) { + return false; + } + + return zend_hash_str_exists(Z_ARRVAL_P(stream_options), ZEND_STRL("error_mode")) + || zend_hash_str_exists(Z_ARRVAL_P(stream_options), ZEND_STRL("error_store")) + || zend_hash_str_exists(Z_ARRVAL_P(stream_options), ZEND_STRL("error_handler")); +} + /* {{{ Set default file/stream context, returns the context as a resource */ PHP_FUNCTION(stream_context_set_default) { @@ -1222,6 +1252,11 @@ PHP_FUNCTION(stream_context_set_default) } context = FG(default_context); + if (php_stream_context_options_has_error_settings(options)) { + zend_value_error("Stream error handling options cannot be set on the default context"); + RETURN_THROWS(); + } + if (parse_context_options(context, options) == FAILURE) { RETURN_THROWS(); } @@ -1636,12 +1671,15 @@ PHP_FUNCTION(stream_resolve_include_path) /* {{{ */ PHP_FUNCTION(stream_is_local) { - zval *zstream; + zval *zstream, *zcontext = NULL; php_stream *stream = NULL; php_stream_wrapper *wrapper = NULL; + php_stream_context *context = NULL; - ZEND_PARSE_PARAMETERS_START(1, 1) + ZEND_PARSE_PARAMETERS_START(1, 2) Z_PARAM_ZVAL(zstream) + Z_PARAM_OPTIONAL + Z_PARAM_RESOURCE_OR_NULL(zcontext) ZEND_PARSE_PARAMETERS_END(); if (Z_TYPE_P(zstream) == IS_RESOURCE) { @@ -1653,8 +1691,9 @@ PHP_FUNCTION(stream_is_local) } php_stream_error_operation_begin(); + context = php_stream_context_from_zval(zcontext, 0); wrapper = php_stream_locate_url_wrapper(Z_STRVAL_P(zstream), NULL, 0); - php_stream_error_operation_end(NULL); + php_stream_error_operation_end(context); } RETURN_BOOL(wrapper && wrapper->is_url == 0); diff --git a/ext/standard/tests/streams/stream_errors_mix_modes_storage.phpt b/ext/standard/tests/streams/stream_errors_mix_modes_storage.phpt index 1dd1972be2c7b..31f2f565a7dc7 100644 --- a/ext/standard/tests/streams/stream_errors_mix_modes_storage.phpt +++ b/ext/standard/tests/streams/stream_errors_mix_modes_storage.phpt @@ -27,18 +27,18 @@ class TestStream { stream_wrapper_register('test', 'TestStream'); -function stream_test_errors($title, $context) { - stream_context_set_default($context); - $stream = fopen('test://foo', 'r', false); +function stream_test_errors($title, $contextOptions) { + $context = stream_context_create($contextOptions); + $stream = fopen('test://foo', 'r', false, $context); try { echo $title . "\n"; - $readin = fopen('php://stdin', 'r'); + $readin = fopen('php://stdin', 'r', false, $context); $data = fread($stream, 10); $read = [$readin, $stream]; $write = NULL; $except = NULL; - stream_select($read, $write, $except, 0); + stream_select($read, $write, $except, 0, 0, $context); } catch (StreamException $e) { echo 'EXCEPTION: ' . $e->getMessage() . "\n"; } diff --git a/ext/standard/tests/streams/stream_errors_set_default_context_error.phpt b/ext/standard/tests/streams/stream_errors_set_default_context_error.phpt new file mode 100644 index 0000000000000..46fc0f7fd34b9 --- /dev/null +++ b/ext/standard/tests/streams/stream_errors_set_default_context_error.phpt @@ -0,0 +1,18 @@ +--TEST-- +Stream errors - prohibit setting error mode in default context +--FILE-- + [ + 'error_mode' => StreamErrorMode::Exception, + ] + ]); +} catch (\ValueError $e) { + echo $e->getMessage() . "\n"; +} + +?> +--EXPECT-- +Stream error handling options cannot be set on the default context From 60180b79e623c992602c88fdbd2536738b3976de Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Sun, 29 Mar 2026 16:28:06 +0200 Subject: [PATCH 64/68] Revert "stream: use StreamError class constants for codes" This reverts commit ba088224e976b9780b73ed2932739ac7825dc048. --- ...flectionExtension_getClassNames_basic.phpt | 1 + .../stream_errors_error_code_helpers.phpt | 10 +- ...stream_errors_exception_mode_terminal.phpt | 2 + .../stream_errors_mix_modes_storage.phpt | 28 +- .../streams/stream_errors_multi_store.phpt | 4 +- .../stream_errors_silent_with_handler.phpt | 4 +- .../stream_errors_silent_with_storage.phpt | 4 +- main/streams/php_stream_errors.h | 186 +++--- main/streams/stream_errors.c | 214 ++++--- main/streams/stream_errors.stub.php | 223 +------- main/streams/stream_errors_arginfo.h | 536 ++---------------- 11 files changed, 325 insertions(+), 887 deletions(-) diff --git a/ext/reflection/tests/ReflectionExtension_getClassNames_basic.phpt b/ext/reflection/tests/ReflectionExtension_getClassNames_basic.phpt index 34a951b45034d..4e985e674f229 100644 --- a/ext/reflection/tests/ReflectionExtension_getClassNames_basic.phpt +++ b/ext/reflection/tests/ReflectionExtension_getClassNames_basic.phpt @@ -17,6 +17,7 @@ Directory RoundingMode StreamBucket StreamError +StreamErrorCode StreamErrorMode StreamErrorStore StreamException diff --git a/ext/standard/tests/streams/stream_errors_error_code_helpers.phpt b/ext/standard/tests/streams/stream_errors_error_code_helpers.phpt index 3a3f939da2998..dc452e846fb4b 100644 --- a/ext/standard/tests/streams/stream_errors_error_code_helpers.phpt +++ b/ext/standard/tests/streams/stream_errors_error_code_helpers.phpt @@ -1,5 +1,5 @@ --TEST-- -Stream errors - StreamError helper methods +Stream errors - StreamErrorCode helper methods --FILE-- isIoError() ? 'yes' : 'no') . "\n"; - echo "Is filesystem error: " . ($error->isFileSystemError() ? 'yes' : 'no') . "\n"; - echo "Is network error: " . ($error->isNetworkError() ? 'yes' : 'no') . "\n"; - echo "Is wrapper error: " . ($error->isWrapperError() ? 'yes' : 'no') . "\n"; + echo "Is I/O error: " . ($error->code->isIoError() ? 'yes' : 'no') . "\n"; + echo "Is filesystem error: " . ($error->code->isFileSystemError() ? 'yes' : 'no') . "\n"; + echo "Is network error: " . ($error->code->isNetworkError() ? 'yes' : 'no') . "\n"; + echo "Is wrapper error: " . ($error->code->isWrapperError() ? 'yes' : 'no') . "\n"; } ?> diff --git a/ext/standard/tests/streams/stream_errors_exception_mode_terminal.phpt b/ext/standard/tests/streams/stream_errors_exception_mode_terminal.phpt index fc3133b65a77b..d66e6d654f1df 100644 --- a/ext/standard/tests/streams/stream_errors_exception_mode_terminal.phpt +++ b/ext/standard/tests/streams/stream_errors_exception_mode_terminal.phpt @@ -18,6 +18,7 @@ try { $error = $e->getError(); if ($error) { echo "Wrapper: " . $error->wrapperName . "\n"; + echo "Error code name: " . $error->code->name . "\n"; } } @@ -26,3 +27,4 @@ try { Caught: Failed to open stream: operation failed Code: 36 Wrapper: PHP +Error code name: OpenFailed diff --git a/ext/standard/tests/streams/stream_errors_mix_modes_storage.phpt b/ext/standard/tests/streams/stream_errors_mix_modes_storage.phpt index 31f2f565a7dc7..1f2ccb8300f5c 100644 --- a/ext/standard/tests/streams/stream_errors_mix_modes_storage.phpt +++ b/ext/standard/tests/streams/stream_errors_mix_modes_storage.phpt @@ -47,7 +47,7 @@ function stream_test_errors($title, $contextOptions) { if ($error) { echo "Error details:\n"; echo "- Message: " . $error->message . "\n"; - echo "- Code: $error->code\n"; + echo "- Code: " . $error->code->name . " (" . $error->code->value . ")\n"; echo "- Wrapper: " . $error->wrapperName . "\n"; echo "- Terminating: " . ($error->terminating ? 'yes' : 'no') . "\n"; echo "- Count: " . $error->count() . "\n"; @@ -56,7 +56,7 @@ function stream_test_errors($title, $contextOptions) { $current = $error; $idx = 0; while ($current) { - echo " [$idx] " . $current->code . ": " . $current->message . "\n"; + echo " [$idx] " . $current->code->name . ": " . $current->message . "\n"; $current = $current->next; $idx++; } @@ -106,41 +106,41 @@ stream_test_errors('AUTO ERROR', [ ALL Error details: - Message: TestStream::stream_cast is not implemented! -- Code: 70 +- Code: NotImplemented (70) - Wrapper: user-space - Terminating: yes - Count: 2 - [0] 70: TestStream::stream_cast is not implemented! - [1] 101: Cannot represent a stream of type user-space as a select()able descriptor + [0] NotImplemented: TestStream::stream_cast is not implemented! + [1] CastNotSupported: Cannot represent a stream of type user-space as a select()able descriptor NON TERMINATING Error details: - Message: TestStream::stream_read - read 10 bytes more data than requested (8202 read, 8192 max) - excess data will be lost -- Code: 161 +- Code: UserspaceInvalidReturn (161) - Wrapper: user-space - Terminating: no - Count: 1 - [0] 161: TestStream::stream_read - read 10 bytes more data than requested (8202 read, 8192 max) - excess data will be lost + [0] UserspaceInvalidReturn: TestStream::stream_read - read 10 bytes more data than requested (8202 read, 8192 max) - excess data will be lost TERMINATING Error details: - Message: TestStream::stream_cast is not implemented! -- Code: 70 +- Code: NotImplemented (70) - Wrapper: user-space - Terminating: yes - Count: 2 - [0] 70: TestStream::stream_cast is not implemented! - [1] 101: Cannot represent a stream of type user-space as a select()able descriptor + [0] NotImplemented: TestStream::stream_cast is not implemented! + [1] CastNotSupported: Cannot represent a stream of type user-space as a select()able descriptor AUTO EXCEPTION EXCEPTION: TestStream::stream_cast is not implemented! Error details: - Message: TestStream::stream_read - read 10 bytes more data than requested (8202 read, 8192 max) - excess data will be lost -- Code: 161 +- Code: UserspaceInvalidReturn (161) - Wrapper: user-space - Terminating: no - Count: 1 - [0] 161: TestStream::stream_read - read 10 bytes more data than requested (8202 read, 8192 max) - excess data will be lost + [0] UserspaceInvalidReturn: TestStream::stream_read - read 10 bytes more data than requested (8202 read, 8192 max) - excess data will be lost AUTO ERROR @@ -151,8 +151,8 @@ Warning: stream_select(): TestStream::stream_cast is not implemented! in %s on l Warning: stream_select(): Cannot represent a stream of type user-space as a select()able descriptor in %s on line %d Error details: - Message: TestStream::stream_read - read 10 bytes more data than requested (8202 read, 8192 max) - excess data will be lost -- Code: 161 +- Code: UserspaceInvalidReturn (161) - Wrapper: user-space - Terminating: no - Count: 1 - [0] 161: TestStream::stream_read - read 10 bytes more data than requested (8202 read, 8192 max) - excess data will be lost + [0] UserspaceInvalidReturn: TestStream::stream_read - read 10 bytes more data than requested (8202 read, 8192 max) - excess data will be lost diff --git a/ext/standard/tests/streams/stream_errors_multi_store.phpt b/ext/standard/tests/streams/stream_errors_multi_store.phpt index 7df5b1f54062a..eccfb065d563c 100644 --- a/ext/standard/tests/streams/stream_errors_multi_store.phpt +++ b/ext/standard/tests/streams/stream_errors_multi_store.phpt @@ -13,8 +13,8 @@ $stream = fopen('php://nonexistent', 'r', false, $context); $error = stream_get_last_error(); if ($error) { - echo "Has OpenFailed: " . ($error->hasCode(StreamError::CODE_OPEN_FAILED) ? 'yes' : 'no') . "\n"; - echo "Has NotFound: " . ($error->hasCode(StreamError::CODE_NOT_FOUND) ? 'yes' : 'no') . "\n"; + echo "Has OpenFailed: " . ($error->hasCode(StreamErrorCode::OpenFailed) ? 'yes' : 'no') . "\n"; + echo "Has NotFound: " . ($error->hasCode(StreamErrorCode::NotFound) ? 'yes' : 'no') . "\n"; } ?> diff --git a/ext/standard/tests/streams/stream_errors_silent_with_handler.phpt b/ext/standard/tests/streams/stream_errors_silent_with_handler.phpt index f552737cf77c5..2416a15529aa5 100644 --- a/ext/standard/tests/streams/stream_errors_silent_with_handler.phpt +++ b/ext/standard/tests/streams/stream_errors_silent_with_handler.phpt @@ -12,7 +12,7 @@ $context = stream_context_create([ $handler_called = true; echo "Handler called\n"; echo "Wrapper: " . $error->wrapperName . "\n"; - echo "Code: " . $error->code . "\n"; + echo "Code: " . $error->code->name . "\n"; echo "Message: " . $error->message . "\n"; echo "Param: " . ($error->param ?? 'null') . "\n"; echo "Terminating: " . ($error->terminating ? 'yes' : 'no') . "\n"; @@ -28,7 +28,7 @@ var_dump($handler_called); --EXPECT-- Handler called Wrapper: PHP -Code: 36 +Code: OpenFailed Message: Failed to open stream: operation failed Param: php://nonexistent Terminating: yes diff --git a/ext/standard/tests/streams/stream_errors_silent_with_storage.phpt b/ext/standard/tests/streams/stream_errors_silent_with_storage.phpt index 5d470572f4800..0d3d627001788 100644 --- a/ext/standard/tests/streams/stream_errors_silent_with_storage.phpt +++ b/ext/standard/tests/streams/stream_errors_silent_with_storage.phpt @@ -15,7 +15,7 @@ var_dump($stream); $error = stream_get_last_error(); if ($error) { echo "Has error: yes\n"; - echo "Error code: " . $error->code . "\n"; + echo "Error code: " . $error->code->name . "\n"; echo "Error wrapper: " . $error->wrapperName . "\n"; echo "Error message: " . $error->message . "\n"; } @@ -24,6 +24,6 @@ if ($error) { --EXPECT-- bool(false) Has error: yes -Error code: 36 +Error code: OpenFailed Error wrapper: PHP Error message: Failed to open stream: operation failed diff --git a/main/streams/php_stream_errors.h b/main/streams/php_stream_errors.h index 936a76f3cfcab..4d64e3905034a 100644 --- a/main/streams/php_stream_errors.h +++ b/main/streams/php_stream_errors.h @@ -61,94 +61,102 @@ BEGIN_EXTERN_C() #define STREAM_ERROR_CODE_USERSPACE_START 160 #define STREAM_ERROR_CODE_USERSPACE_END 170 -/* Error codes - exposed as StreamError::ERROR_CODE_* class constants */ -/* General errors */ -#define STREAM_ERROR_CODE_NONE 0 -#define STREAM_ERROR_CODE_GENERIC 1 -/* I/O operation errors (10-29) */ -#define STREAM_ERROR_CODE_READ_FAILED 10 -#define STREAM_ERROR_CODE_WRITE_FAILED 11 -#define STREAM_ERROR_CODE_SEEK_FAILED 12 -#define STREAM_ERROR_CODE_SEEK_NOT_SUPPORTED 13 -#define STREAM_ERROR_CODE_FLUSH_FAILED 14 -#define STREAM_ERROR_CODE_TRUNCATE_FAILED 15 -#define STREAM_ERROR_CODE_CONNECT_FAILED 16 -#define STREAM_ERROR_CODE_BIND_FAILED 17 -#define STREAM_ERROR_CODE_LISTEN_FAILED 18 -#define STREAM_ERROR_CODE_NOT_WRITABLE 19 -#define STREAM_ERROR_CODE_NOT_READABLE 20 -/* File system operations (30-69) */ -#define STREAM_ERROR_CODE_DISABLED 30 -#define STREAM_ERROR_CODE_NOT_FOUND 31 -#define STREAM_ERROR_CODE_PERMISSION_DENIED 32 -#define STREAM_ERROR_CODE_ALREADY_EXISTS 33 -#define STREAM_ERROR_CODE_INVALID_PATH 34 -#define STREAM_ERROR_CODE_PATH_TOO_LONG 35 -#define STREAM_ERROR_CODE_OPEN_FAILED 36 -#define STREAM_ERROR_CODE_CREATE_FAILED 37 -#define STREAM_ERROR_CODE_DUP_FAILED 38 -#define STREAM_ERROR_CODE_UNLINK_FAILED 39 -#define STREAM_ERROR_CODE_RENAME_FAILED 40 -#define STREAM_ERROR_CODE_MKDIR_FAILED 41 -#define STREAM_ERROR_CODE_RMDIR_FAILED 42 -#define STREAM_ERROR_CODE_STAT_FAILED 43 -#define STREAM_ERROR_CODE_META_FAILED 44 -#define STREAM_ERROR_CODE_CHMOD_FAILED 45 -#define STREAM_ERROR_CODE_CHOWN_FAILED 46 -#define STREAM_ERROR_CODE_COPY_FAILED 47 -#define STREAM_ERROR_CODE_TOUCH_FAILED 48 -#define STREAM_ERROR_CODE_INVALID_MODE 49 -#define STREAM_ERROR_CODE_INVALID_META 50 -#define STREAM_ERROR_CODE_MODE_NOT_SUPPORTED 51 -#define STREAM_ERROR_CODE_READONLY 52 -#define STREAM_ERROR_CODE_RECURSION_DETECTED 53 -/* Wrapper/protocol operations (70-89) */ -#define STREAM_ERROR_CODE_NOT_IMPLEMENTED 70 -#define STREAM_ERROR_CODE_NO_OPENER 71 -#define STREAM_ERROR_CODE_PERSISTENT_NOT_SUPPORTED 72 -#define STREAM_ERROR_CODE_WRAPPER_NOT_FOUND 73 -#define STREAM_ERROR_CODE_WRAPPER_DISABLED 74 -#define STREAM_ERROR_CODE_PROTOCOL_UNSUPPORTED 75 -#define STREAM_ERROR_CODE_WRAPPER_REGISTRATION_FAILED 76 -#define STREAM_ERROR_CODE_WRAPPER_UNREGISTRATION_FAILED 77 -#define STREAM_ERROR_CODE_WRAPPER_RESTORATION_FAILED 78 -/* Filter operations (90-99) */ -#define STREAM_ERROR_CODE_FILTER_NOT_FOUND 90 -#define STREAM_ERROR_CODE_FILTER_FAILED 91 -/* Cast/conversion operations (100-109) */ -#define STREAM_ERROR_CODE_CAST_FAILED 100 -#define STREAM_ERROR_CODE_CAST_NOT_SUPPORTED 101 -#define STREAM_ERROR_CODE_MAKE_SEEKABLE_FAILED 102 -#define STREAM_ERROR_CODE_BUFFERED_DATA_LOST 103 -/* Network/socket operations (110-129) */ -#define STREAM_ERROR_CODE_NETWORK_SEND_FAILED 110 -#define STREAM_ERROR_CODE_NETWORK_RECV_FAILED 111 -#define STREAM_ERROR_CODE_SSL_NOT_SUPPORTED 112 -#define STREAM_ERROR_CODE_RESUMPTION_FAILED 113 -#define STREAM_ERROR_CODE_SOCKET_PATH_TOO_LONG 114 -#define STREAM_ERROR_CODE_OOB_NOT_SUPPORTED 115 -#define STREAM_ERROR_CODE_PROTOCOL_ERROR 116 -#define STREAM_ERROR_CODE_INVALID_URL 117 -#define STREAM_ERROR_CODE_INVALID_RESPONSE 118 -#define STREAM_ERROR_CODE_INVALID_HEADER 119 -#define STREAM_ERROR_CODE_INVALID_PARAM 120 -#define STREAM_ERROR_CODE_REDIRECT_LIMIT 121 -#define STREAM_ERROR_CODE_AUTH_FAILED 122 -/* Encoding/decoding/archiving operations (130-139) */ -#define STREAM_ERROR_CODE_ARCHIVING_FAILED 130 -#define STREAM_ERROR_CODE_ENCODING_FAILED 131 -#define STREAM_ERROR_CODE_DECODING_FAILED 132 -#define STREAM_ERROR_CODE_INVALID_FORMAT 133 -/* Resource/allocation operations (140-149) */ -#define STREAM_ERROR_CODE_ALLOCATION_FAILED 140 -#define STREAM_ERROR_CODE_TEMPORARY_FILE_FAILED 141 -/* Locking operations (150-159) */ -#define STREAM_ERROR_CODE_LOCK_FAILED 150 -#define STREAM_ERROR_CODE_LOCK_NOT_SUPPORTED 151 -/* Userspace stream operations (160-169) */ -#define STREAM_ERROR_CODE_USERSPACE_NOT_IMPLEMENTED 160 -#define STREAM_ERROR_CODE_USERSPACE_INVALID_RETURN 161 -#define STREAM_ERROR_CODE_USERSPACE_CALL_FAILED 162 +/* X-macro defining all error codes */ +#define PHP_STREAM_ERROR_CODES(V) \ + /* General errors */ \ + V(NONE, None, 0) \ + V(GENERIC, Generic, 1) \ + /* I/O operation errors (10-29) */ \ + V(READ_FAILED, ReadFailed, 10) \ + V(WRITE_FAILED, WriteFailed, 11) \ + V(SEEK_FAILED, SeekFailed, 12) \ + V(SEEK_NOT_SUPPORTED, SeekNotSupported, 13) \ + V(FLUSH_FAILED, FlushFailed, 14) \ + V(TRUNCATE_FAILED, TruncateFailed, 15) \ + V(CONNECT_FAILED, ConnectFailed, 16) \ + V(BIND_FAILED, BindFailed, 17) \ + V(LISTEN_FAILED, ListenFailed, 18) \ + V(NOT_WRITABLE, NotWritable, 19) \ + V(NOT_READABLE, NotReadable, 20) \ + /* File system operations (30-69) */ \ + V(DISABLED, Disabled, 30) \ + V(NOT_FOUND, NotFound, 31) \ + V(PERMISSION_DENIED, PermissionDenied, 32) \ + V(ALREADY_EXISTS, AlreadyExists, 33) \ + V(INVALID_PATH, InvalidPath, 34) \ + V(PATH_TOO_LONG, PathTooLong, 35) \ + V(OPEN_FAILED, OpenFailed, 36) \ + V(CREATE_FAILED, CreateFailed, 37) \ + V(DUP_FAILED, DupFailed, 38) \ + V(UNLINK_FAILED, UnlinkFailed, 39) \ + V(RENAME_FAILED, RenameFailed, 40) \ + V(MKDIR_FAILED, MkdirFailed, 41) \ + V(RMDIR_FAILED, RmdirFailed, 42) \ + V(STAT_FAILED, StatFailed, 43) \ + V(META_FAILED, MetaFailed, 44) \ + V(CHMOD_FAILED, ChmodFailed, 45) \ + V(CHOWN_FAILED, ChownFailed, 46) \ + V(COPY_FAILED, CopyFailed, 47) \ + V(TOUCH_FAILED, TouchFailed, 48) \ + V(INVALID_MODE, InvalidMode, 49) \ + V(INVALID_META, InvalidMeta, 50) \ + V(MODE_NOT_SUPPORTED, ModeNotSupported, 51) \ + V(READONLY, Readonly, 52) \ + V(RECURSION_DETECTED, RecursionDetected, 53) \ + /* Wrapper/protocol operations (70-89) */ \ + V(NOT_IMPLEMENTED, NotImplemented, 70) \ + V(NO_OPENER, NoOpener, 71) \ + V(PERSISTENT_NOT_SUPPORTED, PersistentNotSupported, 72) \ + V(WRAPPER_NOT_FOUND, WrapperNotFound, 73) \ + V(WRAPPER_DISABLED, WrapperDisabled, 74) \ + V(PROTOCOL_UNSUPPORTED, ProtocolUnsupported, 75) \ + V(WRAPPER_REGISTRATION_FAILED, WrapperRegistrationFailed, 76) \ + V(WRAPPER_UNREGISTRATION_FAILED, WrapperUnregistrationFailed, 77) \ + V(WRAPPER_RESTORATION_FAILED, WrapperRestorationFailed, 78) \ + /* Filter operations (90-99) */ \ + V(FILTER_NOT_FOUND, FilterNotFound, 90) \ + V(FILTER_FAILED, FilterFailed, 91) \ + /* Cast/conversion operations (100-109) */ \ + V(CAST_FAILED, CastFailed, 100) \ + V(CAST_NOT_SUPPORTED, CastNotSupported, 101) \ + V(MAKE_SEEKABLE_FAILED, MakeSeekableFailed, 102) \ + V(BUFFERED_DATA_LOST, BufferedDataLost, 103) \ + /* Network/socket operations (110-129) */ \ + V(NETWORK_SEND_FAILED, NetworkSendFailed, 110) \ + V(NETWORK_RECV_FAILED, NetworkRecvFailed, 111) \ + V(SSL_NOT_SUPPORTED, SslNotSupported, 112) \ + V(RESUMPTION_FAILED, ResumptionFailed, 113) \ + V(SOCKET_PATH_TOO_LONG, SocketPathTooLong, 114) \ + V(OOB_NOT_SUPPORTED, OobNotSupported, 115) \ + V(PROTOCOL_ERROR, ProtocolError, 116) \ + V(INVALID_URL, InvalidUrl, 117) \ + V(INVALID_RESPONSE, InvalidResponse, 118) \ + V(INVALID_HEADER, InvalidHeader, 119) \ + V(INVALID_PARAM, InvalidParam, 120) \ + V(REDIRECT_LIMIT, RedirectLimit, 121) \ + V(AUTH_FAILED, AuthFailed, 122) \ + /* Encoding/decoding/archiving operations (130-139) */ \ + V(ARCHIVING_FAILED, ArchivingFailed, 130) \ + V(ENCODING_FAILED, EncodingFailed, 131) \ + V(DECODING_FAILED, DecodingFailed, 132) \ + V(INVALID_FORMAT, InvalidFormat, 133) \ + /* Resource/allocation operations (140-149) */ \ + V(ALLOCATION_FAILED, AllocationFailed, 140) \ + V(TEMPORARY_FILE_FAILED, TemporaryFileFailed, 141) \ + /* Locking operations (150-159) */ \ + V(LOCK_FAILED, LockFailed, 150) \ + V(LOCK_NOT_SUPPORTED, LockNotSupported, 151) \ + /* Userspace stream operations (160-169) */ \ + V(USERSPACE_NOT_IMPLEMENTED, UserspaceNotImplemented, 160) \ + V(USERSPACE_INVALID_RETURN, UserspaceInvalidReturn, 161) \ + V(USERSPACE_CALL_FAILED, UserspaceCallFailed, 162) + +/* Generate C enum for internal use */ +typedef enum _StreamErrorCode { +#define V(uc_name, name, val) STREAM_ERROR_CODE_##uc_name = val, + PHP_STREAM_ERROR_CODES(V) +#undef V +} StreamErrorCode; /* Wrapper name for PHP errors */ #define PHP_STREAM_ERROR_WRAPPER_DEFAULT_NAME ":na" @@ -158,7 +166,7 @@ BEGIN_EXTERN_C() /* Error entry in chain */ typedef struct _php_stream_error_entry { zend_string *message; - int code; + StreamErrorCode code; char *wrapper_name; char *param; char *docref; diff --git a/main/streams/stream_errors.c b/main/streams/stream_errors.c index cd10e7eb515c0..4e2b68efd82fb 100644 --- a/main/streams/stream_errors.c +++ b/main/streams/stream_errors.c @@ -24,13 +24,22 @@ #include "stream_errors_arginfo.h" /* Class entries */ +static zend_class_entry *php_ce_stream_error_code; static zend_class_entry *php_ce_stream_error_mode; static zend_class_entry *php_ce_stream_error_store; static zend_class_entry *php_ce_stream_error; static zend_class_entry *php_ce_stream_exception; +/* Lookup table for error code to case name */ +static const char *const php_stream_error_code_names[200] = { +#define V(uc_name, name, val) [val] = #name, + PHP_STREAM_ERROR_CODES(V) +#undef V +}; + /* Forward declarations */ static void php_stream_error_entry_free(php_stream_error_entry *entry); +static bool php_stream_error_code_in_range(zval *this_zv, int start, int end); /* Context option helpers */ @@ -256,7 +265,7 @@ PHPAPI php_stream_error_operation *php_stream_error_operation_begin(void) return op; } -static void php_stream_error_add(int code, const char *wrapper_name, +static void php_stream_error_add(StreamErrorCode code, const char *wrapper_name, zend_string *message, const char *docref, char *param, int severity, bool terminating) { php_stream_error_operation *op = FG(stream_error_state).current_operation; @@ -322,7 +331,7 @@ static void php_stream_throw_exception_with_errors(php_stream_error_operation *o zend_update_property_string(php_ce_stream_exception, Z_OBJ(ex), ZEND_STRL("message"), ZSTR_VAL(op->first_error->message)); - /* Set code from first error code value */ + /* Set code from first error enum value */ zend_update_property_long(php_ce_stream_exception, Z_OBJ(ex), ZEND_STRL("code"), (zend_long) op->first_error->code); @@ -845,7 +854,7 @@ PHPAPI void php_stream_tidy_wrapper_error_log(php_stream_wrapper *wrapper) } } -/* StreamError object creation */ +/* StreamError object creation - no enum cache */ PHPAPI void php_stream_error_create_object(zval *zv, php_stream_error_entry *entry) { @@ -856,9 +865,29 @@ PHPAPI void php_stream_error_create_object(zval *zv, php_stream_error_entry *ent object_init_ex(zv, php_ce_stream_error); - /* Set code as integer */ - zend_update_property_long( - php_ce_stream_error, Z_OBJ_P(zv), ZEND_STRL("code"), (zend_long) entry->code); + /* Get enum case by value using lookup array */ + const char *case_name = NULL; + int code_value = (int) entry->code; + + if (code_value >= 0 + && code_value < (int) (sizeof(php_stream_error_code_names) + / sizeof(php_stream_error_code_names[0]))) { + case_name = php_stream_error_code_names[code_value]; + } + + if (!case_name) { + case_name = "Generic"; + } + + zend_object *enum_obj = zend_enum_get_case_cstr(php_ce_stream_error_code, case_name); + ZEND_ASSERT(enum_obj != NULL); + + zval code_enum; + ZVAL_OBJ(&code_enum, enum_obj); + GC_ADDREF(enum_obj); + + zend_update_property(php_ce_stream_error, Z_OBJ_P(zv), ZEND_STRL("code"), &code_enum); + zval_ptr_dtor(&code_enum); /* Set other properties */ zend_update_property_str( @@ -890,24 +919,88 @@ PHPAPI void php_stream_error_create_object(zval *zv, php_stream_error_entry *ent } } -/* Helper to check if error code is in range */ +/* StreamError methods */ -static bool php_stream_error_code_in_range(zval *this_zv, int start, int end) +PHP_METHOD(StreamError, hasCode) +{ + zval *search_code; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_OBJECT_OF_CLASS(search_code, php_ce_stream_error_code) + ZEND_PARSE_PARAMETERS_END(); + + zval *current_error_zv = ZEND_THIS; + + while (Z_TYPE_P(current_error_zv) == IS_OBJECT) { + zval *code_zv = zend_read_property( + php_ce_stream_error, Z_OBJ_P(current_error_zv), ZEND_STRL("code"), 1, NULL); + + /* Compare enum objects */ + if (Z_TYPE_P(code_zv) == IS_OBJECT && Z_OBJ_P(code_zv) == Z_OBJ_P(search_code)) { + RETURN_TRUE; + } + + /* Move to next error */ + current_error_zv = zend_read_property( + php_ce_stream_error, Z_OBJ_P(current_error_zv), ZEND_STRL("next"), 1, NULL); + + if (Z_TYPE_P(current_error_zv) != IS_OBJECT) { + break; + } + } + + RETURN_FALSE; +} + +PHP_METHOD(StreamError, count) +{ + ZEND_PARSE_PARAMETERS_NONE(); + + zend_long count = 1; + zval *current_error_zv = ZEND_THIS; + + while (1) { + current_error_zv = zend_read_property( + php_ce_stream_error, Z_OBJ_P(current_error_zv), ZEND_STRL("next"), 1, NULL); + + if (Z_TYPE_P(current_error_zv) != IS_OBJECT) { + break; + } + + count++; + } + + RETURN_LONG(count); +} + +/* StreamException methods */ + +PHP_METHOD(StreamException, getError) { - zval *code_zv = zend_read_property( - php_ce_stream_error, Z_OBJ_P(this_zv), ZEND_STRL("code"), 1, NULL); + ZEND_PARSE_PARAMETERS_NONE(); + + zval *error = zend_read_property( + php_ce_stream_exception, Z_OBJ_P(ZEND_THIS), ZEND_STRL("error"), 1, NULL); - if (!code_zv || Z_TYPE_P(code_zv) != IS_LONG) { + RETURN_COPY(error); +} + +/* StreamErrorCode helper */ + +static bool php_stream_error_code_in_range(zval *this_zv, int start, int end) +{ + zval *backing = zend_enum_fetch_case_value(Z_OBJ_P(this_zv)); + if (!backing || Z_TYPE_P(backing) != IS_LONG) { return false; } - zend_long value = Z_LVAL_P(code_zv); + zend_long value = Z_LVAL_P(backing); return value >= start && value < end; } -/* StreamError methods */ +/* StreamErrorCode methods */ -PHP_METHOD(StreamError, isIoError) +PHP_METHOD(StreamErrorCode, isIoError) { ZEND_PARSE_PARAMETERS_NONE(); @@ -915,7 +1008,7 @@ PHP_METHOD(StreamError, isIoError) ZEND_THIS, STREAM_ERROR_CODE_IO_START, STREAM_ERROR_CODE_IO_END)); } -PHP_METHOD(StreamError, isFileSystemError) +PHP_METHOD(StreamErrorCode, isFileSystemError) { ZEND_PARSE_PARAMETERS_NONE(); @@ -923,7 +1016,7 @@ PHP_METHOD(StreamError, isFileSystemError) ZEND_THIS, STREAM_ERROR_CODE_FILESYSTEM_START, STREAM_ERROR_CODE_FILESYSTEM_END)); } -PHP_METHOD(StreamError, isWrapperError) +PHP_METHOD(StreamErrorCode, isWrapperError) { ZEND_PARSE_PARAMETERS_NONE(); @@ -931,7 +1024,7 @@ PHP_METHOD(StreamError, isWrapperError) ZEND_THIS, STREAM_ERROR_CODE_WRAPPER_START, STREAM_ERROR_CODE_WRAPPER_END)); } -PHP_METHOD(StreamError, isFilterError) +PHP_METHOD(StreamErrorCode, isFilterError) { ZEND_PARSE_PARAMETERS_NONE(); @@ -939,7 +1032,7 @@ PHP_METHOD(StreamError, isFilterError) ZEND_THIS, STREAM_ERROR_CODE_FILTER_START, STREAM_ERROR_CODE_FILTER_END)); } -PHP_METHOD(StreamError, isCastError) +PHP_METHOD(StreamErrorCode, isCastError) { ZEND_PARSE_PARAMETERS_NONE(); @@ -947,7 +1040,7 @@ PHP_METHOD(StreamError, isCastError) ZEND_THIS, STREAM_ERROR_CODE_CAST_START, STREAM_ERROR_CODE_CAST_END)); } -PHP_METHOD(StreamError, isNetworkError) +PHP_METHOD(StreamErrorCode, isNetworkError) { ZEND_PARSE_PARAMETERS_NONE(); @@ -955,7 +1048,7 @@ PHP_METHOD(StreamError, isNetworkError) ZEND_THIS, STREAM_ERROR_CODE_NETWORK_START, STREAM_ERROR_CODE_NETWORK_END)); } -PHP_METHOD(StreamError, isEncodingError) +PHP_METHOD(StreamErrorCode, isEncodingError) { ZEND_PARSE_PARAMETERS_NONE(); @@ -963,7 +1056,7 @@ PHP_METHOD(StreamError, isEncodingError) ZEND_THIS, STREAM_ERROR_CODE_ENCODING_START, STREAM_ERROR_CODE_ENCODING_END)); } -PHP_METHOD(StreamError, isResourceError) +PHP_METHOD(StreamErrorCode, isResourceError) { ZEND_PARSE_PARAMETERS_NONE(); @@ -971,7 +1064,7 @@ PHP_METHOD(StreamError, isResourceError) ZEND_THIS, STREAM_ERROR_CODE_RESOURCE_START, STREAM_ERROR_CODE_RESOURCE_END)); } -PHP_METHOD(StreamError, isLockError) +PHP_METHOD(StreamErrorCode, isLockError) { ZEND_PARSE_PARAMETERS_NONE(); @@ -979,7 +1072,7 @@ PHP_METHOD(StreamError, isLockError) ZEND_THIS, STREAM_ERROR_CODE_LOCK_START, STREAM_ERROR_CODE_LOCK_END)); } -PHP_METHOD(StreamError, isUserspaceError) +PHP_METHOD(StreamErrorCode, isUserspaceError) { ZEND_PARSE_PARAMETERS_NONE(); @@ -987,78 +1080,25 @@ PHP_METHOD(StreamError, isUserspaceError) ZEND_THIS, STREAM_ERROR_CODE_USERSPACE_START, STREAM_ERROR_CODE_USERSPACE_END)); } -PHP_METHOD(StreamError, hasCode) -{ - zend_long search_code; - - ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_LONG(search_code) - ZEND_PARSE_PARAMETERS_END(); - - zval *current_error_zv = ZEND_THIS; - - while (Z_TYPE_P(current_error_zv) == IS_OBJECT) { - zval *code_zv = zend_read_property( - php_ce_stream_error, Z_OBJ_P(current_error_zv), ZEND_STRL("code"), 1, NULL); - - /* Compare integer code values */ - if (Z_TYPE_P(code_zv) == IS_LONG && Z_LVAL_P(code_zv) == search_code) { - RETURN_TRUE; - } - - /* Move to next error */ - current_error_zv = zend_read_property( - php_ce_stream_error, Z_OBJ_P(current_error_zv), ZEND_STRL("next"), 1, NULL); - - if (Z_TYPE_P(current_error_zv) != IS_OBJECT) { - break; - } - } - - RETURN_FALSE; -} - -PHP_METHOD(StreamError, count) -{ - ZEND_PARSE_PARAMETERS_NONE(); - - zend_long count = 1; - zval *current_error_zv = ZEND_THIS; - - while (1) { - current_error_zv = zend_read_property( - php_ce_stream_error, Z_OBJ_P(current_error_zv), ZEND_STRL("next"), 1, NULL); - - if (Z_TYPE_P(current_error_zv) != IS_OBJECT) { - break; - } - - count++; - } - - RETURN_LONG(count); -} - -/* StreamException methods */ - -PHP_METHOD(StreamException, getError) -{ - ZEND_PARSE_PARAMETERS_NONE(); - - zval *error = zend_read_property( - php_ce_stream_exception, Z_OBJ_P(ZEND_THIS), ZEND_STRL("error"), 1, NULL); - - RETURN_COPY(error); -} - /* Module init */ PHP_MINIT_FUNCTION(stream_errors) { /* Register enums */ + php_ce_stream_error_code = register_class_StreamErrorCode(); php_ce_stream_error_mode = register_class_StreamErrorMode(); php_ce_stream_error_store = register_class_StreamErrorStore(); + /* Add cases to StreamErrorCode */ +#define V(uc_name, name, val) \ + { \ + zval enum_case_value; \ + ZVAL_LONG(&enum_case_value, val); \ + zend_enum_add_case_cstr(php_ce_stream_error_code, #name, &enum_case_value); \ + } + PHP_STREAM_ERROR_CODES(V) +#undef V + /* Register classes */ php_ce_stream_error = register_class_StreamError(); php_ce_stream_exception = register_class_StreamException(zend_ce_exception); diff --git a/main/streams/stream_errors.stub.php b/main/streams/stream_errors.stub.php index eae801f6c5473..8b6b549a68eb7 100644 --- a/main/streams/stream_errors.stub.php +++ b/main/streams/stream_errors.stub.php @@ -2,6 +2,31 @@ /** @generate-class-entries static */ +enum StreamErrorCode: int +{ + // Error code cases registered in code + + public function isIoError(): bool {} + + public function isFileSystemError(): bool {} + + public function isWrapperError(): bool {} + + public function isFilterError(): bool {} + + public function isCastError(): bool {} + + public function isNetworkError(): bool {} + + public function isEncodingError(): bool {} + + public function isResourceError(): bool {} + + public function isLockError(): bool {} + + public function isUserspaceError(): bool {} +} + enum StreamErrorMode { case Error; @@ -20,181 +45,7 @@ enum StreamErrorStore final readonly class StreamError { - /* General errors */ - /** @cvalue STREAM_ERROR_CODE_NONE */ - public const int CODE_NONE = UNKNOWN; - /** @cvalue STREAM_ERROR_CODE_GENERIC */ - public const int CODE_GENERIC = UNKNOWN; - - /* I/O operation errors (10-29) */ - /** @cvalue STREAM_ERROR_CODE_READ_FAILED */ - public const int CODE_READ_FAILED = UNKNOWN; - /** @cvalue STREAM_ERROR_CODE_WRITE_FAILED */ - public const int CODE_WRITE_FAILED = UNKNOWN; - /** @cvalue STREAM_ERROR_CODE_SEEK_FAILED */ - public const int CODE_SEEK_FAILED = UNKNOWN; - /** @cvalue STREAM_ERROR_CODE_SEEK_NOT_SUPPORTED */ - public const int CODE_SEEK_NOT_SUPPORTED = UNKNOWN; - /** @cvalue STREAM_ERROR_CODE_FLUSH_FAILED */ - public const int CODE_FLUSH_FAILED = UNKNOWN; - /** @cvalue STREAM_ERROR_CODE_TRUNCATE_FAILED */ - public const int CODE_TRUNCATE_FAILED = UNKNOWN; - /** @cvalue STREAM_ERROR_CODE_CONNECT_FAILED */ - public const int CODE_CONNECT_FAILED = UNKNOWN; - /** @cvalue STREAM_ERROR_CODE_BIND_FAILED */ - public const int CODE_BIND_FAILED = UNKNOWN; - /** @cvalue STREAM_ERROR_CODE_LISTEN_FAILED */ - public const int CODE_LISTEN_FAILED = UNKNOWN; - /** @cvalue STREAM_ERROR_CODE_NOT_WRITABLE */ - public const int CODE_NOT_WRITABLE = UNKNOWN; - /** @cvalue STREAM_ERROR_CODE_NOT_READABLE */ - public const int CODE_NOT_READABLE = UNKNOWN; - - /* File system operations (30-69) */ - /** @cvalue STREAM_ERROR_CODE_DISABLED */ - public const int CODE_DISABLED = UNKNOWN; - /** @cvalue STREAM_ERROR_CODE_NOT_FOUND */ - public const int CODE_NOT_FOUND = UNKNOWN; - /** @cvalue STREAM_ERROR_CODE_PERMISSION_DENIED */ - public const int CODE_PERMISSION_DENIED = UNKNOWN; - /** @cvalue STREAM_ERROR_CODE_ALREADY_EXISTS */ - public const int CODE_ALREADY_EXISTS = UNKNOWN; - /** @cvalue STREAM_ERROR_CODE_INVALID_PATH */ - public const int CODE_INVALID_PATH = UNKNOWN; - /** @cvalue STREAM_ERROR_CODE_PATH_TOO_LONG */ - public const int CODE_PATH_TOO_LONG = UNKNOWN; - /** @cvalue STREAM_ERROR_CODE_OPEN_FAILED */ - public const int CODE_OPEN_FAILED = UNKNOWN; - /** @cvalue STREAM_ERROR_CODE_CREATE_FAILED */ - public const int CODE_CREATE_FAILED = UNKNOWN; - /** @cvalue STREAM_ERROR_CODE_DUP_FAILED */ - public const int CODE_DUP_FAILED = UNKNOWN; - /** @cvalue STREAM_ERROR_CODE_UNLINK_FAILED */ - public const int CODE_UNLINK_FAILED = UNKNOWN; - /** @cvalue STREAM_ERROR_CODE_RENAME_FAILED */ - public const int CODE_RENAME_FAILED = UNKNOWN; - /** @cvalue STREAM_ERROR_CODE_MKDIR_FAILED */ - public const int CODE_MKDIR_FAILED = UNKNOWN; - /** @cvalue STREAM_ERROR_CODE_RMDIR_FAILED */ - public const int CODE_RMDIR_FAILED = UNKNOWN; - /** @cvalue STREAM_ERROR_CODE_STAT_FAILED */ - public const int CODE_STAT_FAILED = UNKNOWN; - /** @cvalue STREAM_ERROR_CODE_META_FAILED */ - public const int CODE_META_FAILED = UNKNOWN; - /** @cvalue STREAM_ERROR_CODE_CHMOD_FAILED */ - public const int CODE_CHMOD_FAILED = UNKNOWN; - /** @cvalue STREAM_ERROR_CODE_CHOWN_FAILED */ - public const int CODE_CHOWN_FAILED = UNKNOWN; - /** @cvalue STREAM_ERROR_CODE_COPY_FAILED */ - public const int CODE_COPY_FAILED = UNKNOWN; - /** @cvalue STREAM_ERROR_CODE_TOUCH_FAILED */ - public const int CODE_TOUCH_FAILED = UNKNOWN; - /** @cvalue STREAM_ERROR_CODE_INVALID_MODE */ - public const int CODE_INVALID_MODE = UNKNOWN; - /** @cvalue STREAM_ERROR_CODE_INVALID_META */ - public const int CODE_INVALID_META = UNKNOWN; - /** @cvalue STREAM_ERROR_CODE_MODE_NOT_SUPPORTED */ - public const int CODE_MODE_NOT_SUPPORTED = UNKNOWN; - /** @cvalue STREAM_ERROR_CODE_READONLY */ - public const int CODE_READONLY = UNKNOWN; - /** @cvalue STREAM_ERROR_CODE_RECURSION_DETECTED */ - public const int CODE_RECURSION_DETECTED = UNKNOWN; - - /* Wrapper/protocol operations (70-89) */ - /** @cvalue STREAM_ERROR_CODE_NOT_IMPLEMENTED */ - public const int CODE_NOT_IMPLEMENTED = UNKNOWN; - /** @cvalue STREAM_ERROR_CODE_NO_OPENER */ - public const int CODE_NO_OPENER = UNKNOWN; - /** @cvalue STREAM_ERROR_CODE_PERSISTENT_NOT_SUPPORTED */ - public const int CODE_PERSISTENT_NOT_SUPPORTED = UNKNOWN; - /** @cvalue STREAM_ERROR_CODE_WRAPPER_NOT_FOUND */ - public const int CODE_WRAPPER_NOT_FOUND = UNKNOWN; - /** @cvalue STREAM_ERROR_CODE_WRAPPER_DISABLED */ - public const int CODE_WRAPPER_DISABLED = UNKNOWN; - /** @cvalue STREAM_ERROR_CODE_PROTOCOL_UNSUPPORTED */ - public const int CODE_PROTOCOL_UNSUPPORTED = UNKNOWN; - /** @cvalue STREAM_ERROR_CODE_WRAPPER_REGISTRATION_FAILED */ - public const int CODE_WRAPPER_REGISTRATION_FAILED = UNKNOWN; - /** @cvalue STREAM_ERROR_CODE_WRAPPER_UNREGISTRATION_FAILED */ - public const int CODE_WRAPPER_UNREGISTRATION_FAILED = UNKNOWN; - /** @cvalue STREAM_ERROR_CODE_WRAPPER_RESTORATION_FAILED */ - public const int CODE_WRAPPER_RESTORATION_FAILED = UNKNOWN; - - /* Filter operations (90-99) */ - /** @cvalue STREAM_ERROR_CODE_FILTER_NOT_FOUND */ - public const int CODE_FILTER_NOT_FOUND = UNKNOWN; - /** @cvalue STREAM_ERROR_CODE_FILTER_FAILED */ - public const int CODE_FILTER_FAILED = UNKNOWN; - - /* Cast/conversion operations (100-109) */ - /** @cvalue STREAM_ERROR_CODE_CAST_FAILED */ - public const int CODE_CAST_FAILED = UNKNOWN; - /** @cvalue STREAM_ERROR_CODE_CAST_NOT_SUPPORTED */ - public const int CODE_CAST_NOT_SUPPORTED = UNKNOWN; - /** @cvalue STREAM_ERROR_CODE_MAKE_SEEKABLE_FAILED */ - public const int CODE_MAKE_SEEKABLE_FAILED = UNKNOWN; - /** @cvalue STREAM_ERROR_CODE_BUFFERED_DATA_LOST */ - public const int CODE_BUFFERED_DATA_LOST = UNKNOWN; - - /* Network/socket operations (110-129) */ - /** @cvalue STREAM_ERROR_CODE_NETWORK_SEND_FAILED */ - public const int CODE_NETWORK_SEND_FAILED = UNKNOWN; - /** @cvalue STREAM_ERROR_CODE_NETWORK_RECV_FAILED */ - public const int CODE_NETWORK_RECV_FAILED = UNKNOWN; - /** @cvalue STREAM_ERROR_CODE_SSL_NOT_SUPPORTED */ - public const int CODE_SSL_NOT_SUPPORTED = UNKNOWN; - /** @cvalue STREAM_ERROR_CODE_RESUMPTION_FAILED */ - public const int CODE_RESUMPTION_FAILED = UNKNOWN; - /** @cvalue STREAM_ERROR_CODE_SOCKET_PATH_TOO_LONG */ - public const int CODE_SOCKET_PATH_TOO_LONG = UNKNOWN; - /** @cvalue STREAM_ERROR_CODE_OOB_NOT_SUPPORTED */ - public const int CODE_OOB_NOT_SUPPORTED = UNKNOWN; - /** @cvalue STREAM_ERROR_CODE_PROTOCOL_ERROR */ - public const int CODE_PROTOCOL_ERROR = UNKNOWN; - /** @cvalue STREAM_ERROR_CODE_INVALID_URL */ - public const int CODE_INVALID_URL = UNKNOWN; - /** @cvalue STREAM_ERROR_CODE_INVALID_RESPONSE */ - public const int CODE_INVALID_RESPONSE = UNKNOWN; - /** @cvalue STREAM_ERROR_CODE_INVALID_HEADER */ - public const int CODE_INVALID_HEADER = UNKNOWN; - /** @cvalue STREAM_ERROR_CODE_INVALID_PARAM */ - public const int CODE_INVALID_PARAM = UNKNOWN; - /** @cvalue STREAM_ERROR_CODE_REDIRECT_LIMIT */ - public const int CODE_REDIRECT_LIMIT = UNKNOWN; - /** @cvalue STREAM_ERROR_CODE_AUTH_FAILED */ - public const int CODE_AUTH_FAILED = UNKNOWN; - - /* Encoding/decoding/archiving operations (130-139) */ - /** @cvalue STREAM_ERROR_CODE_ARCHIVING_FAILED */ - public const int CODE_ARCHIVING_FAILED = UNKNOWN; - /** @cvalue STREAM_ERROR_CODE_ENCODING_FAILED */ - public const int CODE_ENCODING_FAILED = UNKNOWN; - /** @cvalue STREAM_ERROR_CODE_DECODING_FAILED */ - public const int CODE_DECODING_FAILED = UNKNOWN; - /** @cvalue STREAM_ERROR_CODE_INVALID_FORMAT */ - public const int CODE_INVALID_FORMAT = UNKNOWN; - - /* Resource/allocation operations (140-149) */ - /** @cvalue STREAM_ERROR_CODE_ALLOCATION_FAILED */ - public const int CODE_ALLOCATION_FAILED = UNKNOWN; - /** @cvalue STREAM_ERROR_CODE_TEMPORARY_FILE_FAILED */ - public const int CODE_TEMPORARY_FILE_FAILED = UNKNOWN; - - /* Locking operations (150-159) */ - /** @cvalue STREAM_ERROR_CODE_LOCK_FAILED */ - public const int CODE_LOCK_FAILED = UNKNOWN; - /** @cvalue STREAM_ERROR_CODE_LOCK_NOT_SUPPORTED */ - public const int CODE_LOCK_NOT_SUPPORTED = UNKNOWN; - - /* Userspace stream operations (160-169) */ - /** @cvalue STREAM_ERROR_CODE_USERSPACE_NOT_IMPLEMENTED */ - public const int CODE_USERSPACE_NOT_IMPLEMENTED = UNKNOWN; - /** @cvalue STREAM_ERROR_CODE_USERSPACE_INVALID_RETURN */ - public const int CODE_USERSPACE_INVALID_RETURN = UNKNOWN; - /** @cvalue STREAM_ERROR_CODE_USERSPACE_CALL_FAILED */ - public const int CODE_USERSPACE_CALL_FAILED = UNKNOWN; - - public int $code; + public StreamErrorCode $code; public string $message; public string $wrapperName; public int $severity; @@ -202,27 +53,7 @@ enum StreamErrorStore public ?string $param; public ?StreamError $next; - public function isIoError(): bool {} - - public function isFileSystemError(): bool {} - - public function isWrapperError(): bool {} - - public function isFilterError(): bool {} - - public function isCastError(): bool {} - - public function isNetworkError(): bool {} - - public function isEncodingError(): bool {} - - public function isResourceError(): bool {} - - public function isLockError(): bool {} - - public function isUserspaceError(): bool {} - - public function hasCode(int $code): bool {} + public function hasCode(StreamErrorCode $code): bool {} public function count(): int {} } diff --git a/main/streams/stream_errors_arginfo.h b/main/streams/stream_errors_arginfo.h index bd2412f2e73c2..7fded66ec89d5 100644 --- a/main/streams/stream_errors_arginfo.h +++ b/main/streams/stream_errors_arginfo.h @@ -1,29 +1,29 @@ -/* This is a generated file, edit stream_errors.stub.php instead. - * Stub hash: d6862fd09e088b7eb6cff766e812bb7246525b76 */ +/* This is a generated file, edit the .stub.php file instead. + * Stub hash: 24a4229f4272983a6fb996ce136ea904183e14e0 */ -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_StreamError_isIoError, 0, 0, _IS_BOOL, 0) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_StreamErrorCode_isIoError, 0, 0, _IS_BOOL, 0) ZEND_END_ARG_INFO() -#define arginfo_class_StreamError_isFileSystemError arginfo_class_StreamError_isIoError +#define arginfo_class_StreamErrorCode_isFileSystemError arginfo_class_StreamErrorCode_isIoError -#define arginfo_class_StreamError_isWrapperError arginfo_class_StreamError_isIoError +#define arginfo_class_StreamErrorCode_isWrapperError arginfo_class_StreamErrorCode_isIoError -#define arginfo_class_StreamError_isFilterError arginfo_class_StreamError_isIoError +#define arginfo_class_StreamErrorCode_isFilterError arginfo_class_StreamErrorCode_isIoError -#define arginfo_class_StreamError_isCastError arginfo_class_StreamError_isIoError +#define arginfo_class_StreamErrorCode_isCastError arginfo_class_StreamErrorCode_isIoError -#define arginfo_class_StreamError_isNetworkError arginfo_class_StreamError_isIoError +#define arginfo_class_StreamErrorCode_isNetworkError arginfo_class_StreamErrorCode_isIoError -#define arginfo_class_StreamError_isEncodingError arginfo_class_StreamError_isIoError +#define arginfo_class_StreamErrorCode_isEncodingError arginfo_class_StreamErrorCode_isIoError -#define arginfo_class_StreamError_isResourceError arginfo_class_StreamError_isIoError +#define arginfo_class_StreamErrorCode_isResourceError arginfo_class_StreamErrorCode_isIoError -#define arginfo_class_StreamError_isLockError arginfo_class_StreamError_isIoError +#define arginfo_class_StreamErrorCode_isLockError arginfo_class_StreamErrorCode_isIoError -#define arginfo_class_StreamError_isUserspaceError arginfo_class_StreamError_isIoError +#define arginfo_class_StreamErrorCode_isUserspaceError arginfo_class_StreamErrorCode_isIoError ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_StreamError_hasCode, 0, 1, _IS_BOOL, 0) - ZEND_ARG_TYPE_INFO(0, code, IS_LONG, 0) + ZEND_ARG_OBJ_INFO(0, code, StreamErrorCode, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_StreamError_count, 0, 0, IS_LONG, 0) @@ -32,31 +32,35 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_StreamException_getError, 0, 0, StreamError, 1) ZEND_END_ARG_INFO() -static ZEND_METHOD(StreamError, isIoError); -static ZEND_METHOD(StreamError, isFileSystemError); -static ZEND_METHOD(StreamError, isWrapperError); -static ZEND_METHOD(StreamError, isFilterError); -static ZEND_METHOD(StreamError, isCastError); -static ZEND_METHOD(StreamError, isNetworkError); -static ZEND_METHOD(StreamError, isEncodingError); -static ZEND_METHOD(StreamError, isResourceError); -static ZEND_METHOD(StreamError, isLockError); -static ZEND_METHOD(StreamError, isUserspaceError); +static ZEND_METHOD(StreamErrorCode, isIoError); +static ZEND_METHOD(StreamErrorCode, isFileSystemError); +static ZEND_METHOD(StreamErrorCode, isWrapperError); +static ZEND_METHOD(StreamErrorCode, isFilterError); +static ZEND_METHOD(StreamErrorCode, isCastError); +static ZEND_METHOD(StreamErrorCode, isNetworkError); +static ZEND_METHOD(StreamErrorCode, isEncodingError); +static ZEND_METHOD(StreamErrorCode, isResourceError); +static ZEND_METHOD(StreamErrorCode, isLockError); +static ZEND_METHOD(StreamErrorCode, isUserspaceError); static ZEND_METHOD(StreamError, hasCode); static ZEND_METHOD(StreamError, count); static ZEND_METHOD(StreamException, getError); +static const zend_function_entry class_StreamErrorCode_methods[] = { + ZEND_ME(StreamErrorCode, isIoError, arginfo_class_StreamErrorCode_isIoError, ZEND_ACC_PUBLIC) + ZEND_ME(StreamErrorCode, isFileSystemError, arginfo_class_StreamErrorCode_isFileSystemError, ZEND_ACC_PUBLIC) + ZEND_ME(StreamErrorCode, isWrapperError, arginfo_class_StreamErrorCode_isWrapperError, ZEND_ACC_PUBLIC) + ZEND_ME(StreamErrorCode, isFilterError, arginfo_class_StreamErrorCode_isFilterError, ZEND_ACC_PUBLIC) + ZEND_ME(StreamErrorCode, isCastError, arginfo_class_StreamErrorCode_isCastError, ZEND_ACC_PUBLIC) + ZEND_ME(StreamErrorCode, isNetworkError, arginfo_class_StreamErrorCode_isNetworkError, ZEND_ACC_PUBLIC) + ZEND_ME(StreamErrorCode, isEncodingError, arginfo_class_StreamErrorCode_isEncodingError, ZEND_ACC_PUBLIC) + ZEND_ME(StreamErrorCode, isResourceError, arginfo_class_StreamErrorCode_isResourceError, ZEND_ACC_PUBLIC) + ZEND_ME(StreamErrorCode, isLockError, arginfo_class_StreamErrorCode_isLockError, ZEND_ACC_PUBLIC) + ZEND_ME(StreamErrorCode, isUserspaceError, arginfo_class_StreamErrorCode_isUserspaceError, ZEND_ACC_PUBLIC) + ZEND_FE_END +}; + static const zend_function_entry class_StreamError_methods[] = { - ZEND_ME(StreamError, isIoError, arginfo_class_StreamError_isIoError, ZEND_ACC_PUBLIC) - ZEND_ME(StreamError, isFileSystemError, arginfo_class_StreamError_isFileSystemError, ZEND_ACC_PUBLIC) - ZEND_ME(StreamError, isWrapperError, arginfo_class_StreamError_isWrapperError, ZEND_ACC_PUBLIC) - ZEND_ME(StreamError, isFilterError, arginfo_class_StreamError_isFilterError, ZEND_ACC_PUBLIC) - ZEND_ME(StreamError, isCastError, arginfo_class_StreamError_isCastError, ZEND_ACC_PUBLIC) - ZEND_ME(StreamError, isNetworkError, arginfo_class_StreamError_isNetworkError, ZEND_ACC_PUBLIC) - ZEND_ME(StreamError, isEncodingError, arginfo_class_StreamError_isEncodingError, ZEND_ACC_PUBLIC) - ZEND_ME(StreamError, isResourceError, arginfo_class_StreamError_isResourceError, ZEND_ACC_PUBLIC) - ZEND_ME(StreamError, isLockError, arginfo_class_StreamError_isLockError, ZEND_ACC_PUBLIC) - ZEND_ME(StreamError, isUserspaceError, arginfo_class_StreamError_isUserspaceError, ZEND_ACC_PUBLIC) ZEND_ME(StreamError, hasCode, arginfo_class_StreamError_hasCode, ZEND_ACC_PUBLIC) ZEND_ME(StreamError, count, arginfo_class_StreamError_count, ZEND_ACC_PUBLIC) ZEND_FE_END @@ -67,6 +71,13 @@ static const zend_function_entry class_StreamException_methods[] = { ZEND_FE_END }; +static zend_class_entry *register_class_StreamErrorCode(void) +{ + zend_class_entry *class_entry = zend_register_internal_enum("StreamErrorCode", IS_LONG, class_StreamErrorCode_methods); + + return class_entry; +} + static zend_class_entry *register_class_StreamErrorMode(void) { zend_class_entry *class_entry = zend_register_internal_enum("StreamErrorMode", IS_UNDEF, NULL); @@ -104,465 +115,10 @@ static zend_class_entry *register_class_StreamError(void) INIT_CLASS_ENTRY(ce, "StreamError", class_StreamError_methods); class_entry = zend_register_internal_class_with_flags(&ce, NULL, ZEND_ACC_FINAL|ZEND_ACC_READONLY_CLASS); - zval const_CODE_NONE_value; - ZVAL_LONG(&const_CODE_NONE_value, STREAM_ERROR_CODE_NONE); - zend_string *const_CODE_NONE_name = zend_string_init_interned("CODE_NONE", sizeof("CODE_NONE") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_NONE_name, &const_CODE_NONE_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_NONE_name, true); - - zval const_CODE_GENERIC_value; - ZVAL_LONG(&const_CODE_GENERIC_value, STREAM_ERROR_CODE_GENERIC); - zend_string *const_CODE_GENERIC_name = zend_string_init_interned("CODE_GENERIC", sizeof("CODE_GENERIC") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_GENERIC_name, &const_CODE_GENERIC_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_GENERIC_name, true); - - zval const_CODE_READ_FAILED_value; - ZVAL_LONG(&const_CODE_READ_FAILED_value, STREAM_ERROR_CODE_READ_FAILED); - zend_string *const_CODE_READ_FAILED_name = zend_string_init_interned("CODE_READ_FAILED", sizeof("CODE_READ_FAILED") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_READ_FAILED_name, &const_CODE_READ_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_READ_FAILED_name, true); - - zval const_CODE_WRITE_FAILED_value; - ZVAL_LONG(&const_CODE_WRITE_FAILED_value, STREAM_ERROR_CODE_WRITE_FAILED); - zend_string *const_CODE_WRITE_FAILED_name = zend_string_init_interned("CODE_WRITE_FAILED", sizeof("CODE_WRITE_FAILED") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_WRITE_FAILED_name, &const_CODE_WRITE_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_WRITE_FAILED_name, true); - - zval const_CODE_SEEK_FAILED_value; - ZVAL_LONG(&const_CODE_SEEK_FAILED_value, STREAM_ERROR_CODE_SEEK_FAILED); - zend_string *const_CODE_SEEK_FAILED_name = zend_string_init_interned("CODE_SEEK_FAILED", sizeof("CODE_SEEK_FAILED") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_SEEK_FAILED_name, &const_CODE_SEEK_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_SEEK_FAILED_name, true); - - zval const_CODE_SEEK_NOT_SUPPORTED_value; - ZVAL_LONG(&const_CODE_SEEK_NOT_SUPPORTED_value, STREAM_ERROR_CODE_SEEK_NOT_SUPPORTED); - zend_string *const_CODE_SEEK_NOT_SUPPORTED_name = zend_string_init_interned("CODE_SEEK_NOT_SUPPORTED", sizeof("CODE_SEEK_NOT_SUPPORTED") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_SEEK_NOT_SUPPORTED_name, &const_CODE_SEEK_NOT_SUPPORTED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_SEEK_NOT_SUPPORTED_name, true); - - zval const_CODE_FLUSH_FAILED_value; - ZVAL_LONG(&const_CODE_FLUSH_FAILED_value, STREAM_ERROR_CODE_FLUSH_FAILED); - zend_string *const_CODE_FLUSH_FAILED_name = zend_string_init_interned("CODE_FLUSH_FAILED", sizeof("CODE_FLUSH_FAILED") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_FLUSH_FAILED_name, &const_CODE_FLUSH_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_FLUSH_FAILED_name, true); - - zval const_CODE_TRUNCATE_FAILED_value; - ZVAL_LONG(&const_CODE_TRUNCATE_FAILED_value, STREAM_ERROR_CODE_TRUNCATE_FAILED); - zend_string *const_CODE_TRUNCATE_FAILED_name = zend_string_init_interned("CODE_TRUNCATE_FAILED", sizeof("CODE_TRUNCATE_FAILED") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_TRUNCATE_FAILED_name, &const_CODE_TRUNCATE_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_TRUNCATE_FAILED_name, true); - - zval const_CODE_CONNECT_FAILED_value; - ZVAL_LONG(&const_CODE_CONNECT_FAILED_value, STREAM_ERROR_CODE_CONNECT_FAILED); - zend_string *const_CODE_CONNECT_FAILED_name = zend_string_init_interned("CODE_CONNECT_FAILED", sizeof("CODE_CONNECT_FAILED") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_CONNECT_FAILED_name, &const_CODE_CONNECT_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_CONNECT_FAILED_name, true); - - zval const_CODE_BIND_FAILED_value; - ZVAL_LONG(&const_CODE_BIND_FAILED_value, STREAM_ERROR_CODE_BIND_FAILED); - zend_string *const_CODE_BIND_FAILED_name = zend_string_init_interned("CODE_BIND_FAILED", sizeof("CODE_BIND_FAILED") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_BIND_FAILED_name, &const_CODE_BIND_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_BIND_FAILED_name, true); - - zval const_CODE_LISTEN_FAILED_value; - ZVAL_LONG(&const_CODE_LISTEN_FAILED_value, STREAM_ERROR_CODE_LISTEN_FAILED); - zend_string *const_CODE_LISTEN_FAILED_name = zend_string_init_interned("CODE_LISTEN_FAILED", sizeof("CODE_LISTEN_FAILED") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_LISTEN_FAILED_name, &const_CODE_LISTEN_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_LISTEN_FAILED_name, true); - - zval const_CODE_NOT_WRITABLE_value; - ZVAL_LONG(&const_CODE_NOT_WRITABLE_value, STREAM_ERROR_CODE_NOT_WRITABLE); - zend_string *const_CODE_NOT_WRITABLE_name = zend_string_init_interned("CODE_NOT_WRITABLE", sizeof("CODE_NOT_WRITABLE") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_NOT_WRITABLE_name, &const_CODE_NOT_WRITABLE_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_NOT_WRITABLE_name, true); - - zval const_CODE_NOT_READABLE_value; - ZVAL_LONG(&const_CODE_NOT_READABLE_value, STREAM_ERROR_CODE_NOT_READABLE); - zend_string *const_CODE_NOT_READABLE_name = zend_string_init_interned("CODE_NOT_READABLE", sizeof("CODE_NOT_READABLE") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_NOT_READABLE_name, &const_CODE_NOT_READABLE_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_NOT_READABLE_name, true); - - zval const_CODE_DISABLED_value; - ZVAL_LONG(&const_CODE_DISABLED_value, STREAM_ERROR_CODE_DISABLED); - zend_string *const_CODE_DISABLED_name = zend_string_init_interned("CODE_DISABLED", sizeof("CODE_DISABLED") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_DISABLED_name, &const_CODE_DISABLED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_DISABLED_name, true); - - zval const_CODE_NOT_FOUND_value; - ZVAL_LONG(&const_CODE_NOT_FOUND_value, STREAM_ERROR_CODE_NOT_FOUND); - zend_string *const_CODE_NOT_FOUND_name = zend_string_init_interned("CODE_NOT_FOUND", sizeof("CODE_NOT_FOUND") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_NOT_FOUND_name, &const_CODE_NOT_FOUND_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_NOT_FOUND_name, true); - - zval const_CODE_PERMISSION_DENIED_value; - ZVAL_LONG(&const_CODE_PERMISSION_DENIED_value, STREAM_ERROR_CODE_PERMISSION_DENIED); - zend_string *const_CODE_PERMISSION_DENIED_name = zend_string_init_interned("CODE_PERMISSION_DENIED", sizeof("CODE_PERMISSION_DENIED") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_PERMISSION_DENIED_name, &const_CODE_PERMISSION_DENIED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_PERMISSION_DENIED_name, true); - - zval const_CODE_ALREADY_EXISTS_value; - ZVAL_LONG(&const_CODE_ALREADY_EXISTS_value, STREAM_ERROR_CODE_ALREADY_EXISTS); - zend_string *const_CODE_ALREADY_EXISTS_name = zend_string_init_interned("CODE_ALREADY_EXISTS", sizeof("CODE_ALREADY_EXISTS") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_ALREADY_EXISTS_name, &const_CODE_ALREADY_EXISTS_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_ALREADY_EXISTS_name, true); - - zval const_CODE_INVALID_PATH_value; - ZVAL_LONG(&const_CODE_INVALID_PATH_value, STREAM_ERROR_CODE_INVALID_PATH); - zend_string *const_CODE_INVALID_PATH_name = zend_string_init_interned("CODE_INVALID_PATH", sizeof("CODE_INVALID_PATH") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_INVALID_PATH_name, &const_CODE_INVALID_PATH_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_INVALID_PATH_name, true); - - zval const_CODE_PATH_TOO_LONG_value; - ZVAL_LONG(&const_CODE_PATH_TOO_LONG_value, STREAM_ERROR_CODE_PATH_TOO_LONG); - zend_string *const_CODE_PATH_TOO_LONG_name = zend_string_init_interned("CODE_PATH_TOO_LONG", sizeof("CODE_PATH_TOO_LONG") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_PATH_TOO_LONG_name, &const_CODE_PATH_TOO_LONG_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_PATH_TOO_LONG_name, true); - - zval const_CODE_OPEN_FAILED_value; - ZVAL_LONG(&const_CODE_OPEN_FAILED_value, STREAM_ERROR_CODE_OPEN_FAILED); - zend_string *const_CODE_OPEN_FAILED_name = zend_string_init_interned("CODE_OPEN_FAILED", sizeof("CODE_OPEN_FAILED") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_OPEN_FAILED_name, &const_CODE_OPEN_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_OPEN_FAILED_name, true); - - zval const_CODE_CREATE_FAILED_value; - ZVAL_LONG(&const_CODE_CREATE_FAILED_value, STREAM_ERROR_CODE_CREATE_FAILED); - zend_string *const_CODE_CREATE_FAILED_name = zend_string_init_interned("CODE_CREATE_FAILED", sizeof("CODE_CREATE_FAILED") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_CREATE_FAILED_name, &const_CODE_CREATE_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_CREATE_FAILED_name, true); - - zval const_CODE_DUP_FAILED_value; - ZVAL_LONG(&const_CODE_DUP_FAILED_value, STREAM_ERROR_CODE_DUP_FAILED); - zend_string *const_CODE_DUP_FAILED_name = zend_string_init_interned("CODE_DUP_FAILED", sizeof("CODE_DUP_FAILED") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_DUP_FAILED_name, &const_CODE_DUP_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_DUP_FAILED_name, true); - - zval const_CODE_UNLINK_FAILED_value; - ZVAL_LONG(&const_CODE_UNLINK_FAILED_value, STREAM_ERROR_CODE_UNLINK_FAILED); - zend_string *const_CODE_UNLINK_FAILED_name = zend_string_init_interned("CODE_UNLINK_FAILED", sizeof("CODE_UNLINK_FAILED") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_UNLINK_FAILED_name, &const_CODE_UNLINK_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_UNLINK_FAILED_name, true); - - zval const_CODE_RENAME_FAILED_value; - ZVAL_LONG(&const_CODE_RENAME_FAILED_value, STREAM_ERROR_CODE_RENAME_FAILED); - zend_string *const_CODE_RENAME_FAILED_name = zend_string_init_interned("CODE_RENAME_FAILED", sizeof("CODE_RENAME_FAILED") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_RENAME_FAILED_name, &const_CODE_RENAME_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_RENAME_FAILED_name, true); - - zval const_CODE_MKDIR_FAILED_value; - ZVAL_LONG(&const_CODE_MKDIR_FAILED_value, STREAM_ERROR_CODE_MKDIR_FAILED); - zend_string *const_CODE_MKDIR_FAILED_name = zend_string_init_interned("CODE_MKDIR_FAILED", sizeof("CODE_MKDIR_FAILED") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_MKDIR_FAILED_name, &const_CODE_MKDIR_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_MKDIR_FAILED_name, true); - - zval const_CODE_RMDIR_FAILED_value; - ZVAL_LONG(&const_CODE_RMDIR_FAILED_value, STREAM_ERROR_CODE_RMDIR_FAILED); - zend_string *const_CODE_RMDIR_FAILED_name = zend_string_init_interned("CODE_RMDIR_FAILED", sizeof("CODE_RMDIR_FAILED") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_RMDIR_FAILED_name, &const_CODE_RMDIR_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_RMDIR_FAILED_name, true); - - zval const_CODE_STAT_FAILED_value; - ZVAL_LONG(&const_CODE_STAT_FAILED_value, STREAM_ERROR_CODE_STAT_FAILED); - zend_string *const_CODE_STAT_FAILED_name = zend_string_init_interned("CODE_STAT_FAILED", sizeof("CODE_STAT_FAILED") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_STAT_FAILED_name, &const_CODE_STAT_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_STAT_FAILED_name, true); - - zval const_CODE_META_FAILED_value; - ZVAL_LONG(&const_CODE_META_FAILED_value, STREAM_ERROR_CODE_META_FAILED); - zend_string *const_CODE_META_FAILED_name = zend_string_init_interned("CODE_META_FAILED", sizeof("CODE_META_FAILED") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_META_FAILED_name, &const_CODE_META_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_META_FAILED_name, true); - - zval const_CODE_CHMOD_FAILED_value; - ZVAL_LONG(&const_CODE_CHMOD_FAILED_value, STREAM_ERROR_CODE_CHMOD_FAILED); - zend_string *const_CODE_CHMOD_FAILED_name = zend_string_init_interned("CODE_CHMOD_FAILED", sizeof("CODE_CHMOD_FAILED") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_CHMOD_FAILED_name, &const_CODE_CHMOD_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_CHMOD_FAILED_name, true); - - zval const_CODE_CHOWN_FAILED_value; - ZVAL_LONG(&const_CODE_CHOWN_FAILED_value, STREAM_ERROR_CODE_CHOWN_FAILED); - zend_string *const_CODE_CHOWN_FAILED_name = zend_string_init_interned("CODE_CHOWN_FAILED", sizeof("CODE_CHOWN_FAILED") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_CHOWN_FAILED_name, &const_CODE_CHOWN_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_CHOWN_FAILED_name, true); - - zval const_CODE_COPY_FAILED_value; - ZVAL_LONG(&const_CODE_COPY_FAILED_value, STREAM_ERROR_CODE_COPY_FAILED); - zend_string *const_CODE_COPY_FAILED_name = zend_string_init_interned("CODE_COPY_FAILED", sizeof("CODE_COPY_FAILED") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_COPY_FAILED_name, &const_CODE_COPY_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_COPY_FAILED_name, true); - - zval const_CODE_TOUCH_FAILED_value; - ZVAL_LONG(&const_CODE_TOUCH_FAILED_value, STREAM_ERROR_CODE_TOUCH_FAILED); - zend_string *const_CODE_TOUCH_FAILED_name = zend_string_init_interned("CODE_TOUCH_FAILED", sizeof("CODE_TOUCH_FAILED") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_TOUCH_FAILED_name, &const_CODE_TOUCH_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_TOUCH_FAILED_name, true); - - zval const_CODE_INVALID_MODE_value; - ZVAL_LONG(&const_CODE_INVALID_MODE_value, STREAM_ERROR_CODE_INVALID_MODE); - zend_string *const_CODE_INVALID_MODE_name = zend_string_init_interned("CODE_INVALID_MODE", sizeof("CODE_INVALID_MODE") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_INVALID_MODE_name, &const_CODE_INVALID_MODE_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_INVALID_MODE_name, true); - - zval const_CODE_INVALID_META_value; - ZVAL_LONG(&const_CODE_INVALID_META_value, STREAM_ERROR_CODE_INVALID_META); - zend_string *const_CODE_INVALID_META_name = zend_string_init_interned("CODE_INVALID_META", sizeof("CODE_INVALID_META") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_INVALID_META_name, &const_CODE_INVALID_META_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_INVALID_META_name, true); - - zval const_CODE_MODE_NOT_SUPPORTED_value; - ZVAL_LONG(&const_CODE_MODE_NOT_SUPPORTED_value, STREAM_ERROR_CODE_MODE_NOT_SUPPORTED); - zend_string *const_CODE_MODE_NOT_SUPPORTED_name = zend_string_init_interned("CODE_MODE_NOT_SUPPORTED", sizeof("CODE_MODE_NOT_SUPPORTED") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_MODE_NOT_SUPPORTED_name, &const_CODE_MODE_NOT_SUPPORTED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_MODE_NOT_SUPPORTED_name, true); - - zval const_CODE_READONLY_value; - ZVAL_LONG(&const_CODE_READONLY_value, STREAM_ERROR_CODE_READONLY); - zend_string *const_CODE_READONLY_name = zend_string_init_interned("CODE_READONLY", sizeof("CODE_READONLY") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_READONLY_name, &const_CODE_READONLY_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_READONLY_name, true); - - zval const_CODE_RECURSION_DETECTED_value; - ZVAL_LONG(&const_CODE_RECURSION_DETECTED_value, STREAM_ERROR_CODE_RECURSION_DETECTED); - zend_string *const_CODE_RECURSION_DETECTED_name = zend_string_init_interned("CODE_RECURSION_DETECTED", sizeof("CODE_RECURSION_DETECTED") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_RECURSION_DETECTED_name, &const_CODE_RECURSION_DETECTED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_RECURSION_DETECTED_name, true); - - zval const_CODE_NOT_IMPLEMENTED_value; - ZVAL_LONG(&const_CODE_NOT_IMPLEMENTED_value, STREAM_ERROR_CODE_NOT_IMPLEMENTED); - zend_string *const_CODE_NOT_IMPLEMENTED_name = zend_string_init_interned("CODE_NOT_IMPLEMENTED", sizeof("CODE_NOT_IMPLEMENTED") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_NOT_IMPLEMENTED_name, &const_CODE_NOT_IMPLEMENTED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_NOT_IMPLEMENTED_name, true); - - zval const_CODE_NO_OPENER_value; - ZVAL_LONG(&const_CODE_NO_OPENER_value, STREAM_ERROR_CODE_NO_OPENER); - zend_string *const_CODE_NO_OPENER_name = zend_string_init_interned("CODE_NO_OPENER", sizeof("CODE_NO_OPENER") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_NO_OPENER_name, &const_CODE_NO_OPENER_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_NO_OPENER_name, true); - - zval const_CODE_PERSISTENT_NOT_SUPPORTED_value; - ZVAL_LONG(&const_CODE_PERSISTENT_NOT_SUPPORTED_value, STREAM_ERROR_CODE_PERSISTENT_NOT_SUPPORTED); - zend_string *const_CODE_PERSISTENT_NOT_SUPPORTED_name = zend_string_init_interned("CODE_PERSISTENT_NOT_SUPPORTED", sizeof("CODE_PERSISTENT_NOT_SUPPORTED") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_PERSISTENT_NOT_SUPPORTED_name, &const_CODE_PERSISTENT_NOT_SUPPORTED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_PERSISTENT_NOT_SUPPORTED_name, true); - - zval const_CODE_WRAPPER_NOT_FOUND_value; - ZVAL_LONG(&const_CODE_WRAPPER_NOT_FOUND_value, STREAM_ERROR_CODE_WRAPPER_NOT_FOUND); - zend_string *const_CODE_WRAPPER_NOT_FOUND_name = zend_string_init_interned("CODE_WRAPPER_NOT_FOUND", sizeof("CODE_WRAPPER_NOT_FOUND") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_WRAPPER_NOT_FOUND_name, &const_CODE_WRAPPER_NOT_FOUND_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_WRAPPER_NOT_FOUND_name, true); - - zval const_CODE_WRAPPER_DISABLED_value; - ZVAL_LONG(&const_CODE_WRAPPER_DISABLED_value, STREAM_ERROR_CODE_WRAPPER_DISABLED); - zend_string *const_CODE_WRAPPER_DISABLED_name = zend_string_init_interned("CODE_WRAPPER_DISABLED", sizeof("CODE_WRAPPER_DISABLED") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_WRAPPER_DISABLED_name, &const_CODE_WRAPPER_DISABLED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_WRAPPER_DISABLED_name, true); - - zval const_CODE_PROTOCOL_UNSUPPORTED_value; - ZVAL_LONG(&const_CODE_PROTOCOL_UNSUPPORTED_value, STREAM_ERROR_CODE_PROTOCOL_UNSUPPORTED); - zend_string *const_CODE_PROTOCOL_UNSUPPORTED_name = zend_string_init_interned("CODE_PROTOCOL_UNSUPPORTED", sizeof("CODE_PROTOCOL_UNSUPPORTED") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_PROTOCOL_UNSUPPORTED_name, &const_CODE_PROTOCOL_UNSUPPORTED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_PROTOCOL_UNSUPPORTED_name, true); - - zval const_CODE_WRAPPER_REGISTRATION_FAILED_value; - ZVAL_LONG(&const_CODE_WRAPPER_REGISTRATION_FAILED_value, STREAM_ERROR_CODE_WRAPPER_REGISTRATION_FAILED); - zend_string *const_CODE_WRAPPER_REGISTRATION_FAILED_name = zend_string_init_interned("CODE_WRAPPER_REGISTRATION_FAILED", sizeof("CODE_WRAPPER_REGISTRATION_FAILED") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_WRAPPER_REGISTRATION_FAILED_name, &const_CODE_WRAPPER_REGISTRATION_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_WRAPPER_REGISTRATION_FAILED_name, true); - - zval const_CODE_WRAPPER_UNREGISTRATION_FAILED_value; - ZVAL_LONG(&const_CODE_WRAPPER_UNREGISTRATION_FAILED_value, STREAM_ERROR_CODE_WRAPPER_UNREGISTRATION_FAILED); - zend_string *const_CODE_WRAPPER_UNREGISTRATION_FAILED_name = zend_string_init_interned("CODE_WRAPPER_UNREGISTRATION_FAILED", sizeof("CODE_WRAPPER_UNREGISTRATION_FAILED") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_WRAPPER_UNREGISTRATION_FAILED_name, &const_CODE_WRAPPER_UNREGISTRATION_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_WRAPPER_UNREGISTRATION_FAILED_name, true); - - zval const_CODE_WRAPPER_RESTORATION_FAILED_value; - ZVAL_LONG(&const_CODE_WRAPPER_RESTORATION_FAILED_value, STREAM_ERROR_CODE_WRAPPER_RESTORATION_FAILED); - zend_string *const_CODE_WRAPPER_RESTORATION_FAILED_name = zend_string_init_interned("CODE_WRAPPER_RESTORATION_FAILED", sizeof("CODE_WRAPPER_RESTORATION_FAILED") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_WRAPPER_RESTORATION_FAILED_name, &const_CODE_WRAPPER_RESTORATION_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_WRAPPER_RESTORATION_FAILED_name, true); - - zval const_CODE_FILTER_NOT_FOUND_value; - ZVAL_LONG(&const_CODE_FILTER_NOT_FOUND_value, STREAM_ERROR_CODE_FILTER_NOT_FOUND); - zend_string *const_CODE_FILTER_NOT_FOUND_name = zend_string_init_interned("CODE_FILTER_NOT_FOUND", sizeof("CODE_FILTER_NOT_FOUND") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_FILTER_NOT_FOUND_name, &const_CODE_FILTER_NOT_FOUND_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_FILTER_NOT_FOUND_name, true); - - zval const_CODE_FILTER_FAILED_value; - ZVAL_LONG(&const_CODE_FILTER_FAILED_value, STREAM_ERROR_CODE_FILTER_FAILED); - zend_string *const_CODE_FILTER_FAILED_name = zend_string_init_interned("CODE_FILTER_FAILED", sizeof("CODE_FILTER_FAILED") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_FILTER_FAILED_name, &const_CODE_FILTER_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_FILTER_FAILED_name, true); - - zval const_CODE_CAST_FAILED_value; - ZVAL_LONG(&const_CODE_CAST_FAILED_value, STREAM_ERROR_CODE_CAST_FAILED); - zend_string *const_CODE_CAST_FAILED_name = zend_string_init_interned("CODE_CAST_FAILED", sizeof("CODE_CAST_FAILED") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_CAST_FAILED_name, &const_CODE_CAST_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_CAST_FAILED_name, true); - - zval const_CODE_CAST_NOT_SUPPORTED_value; - ZVAL_LONG(&const_CODE_CAST_NOT_SUPPORTED_value, STREAM_ERROR_CODE_CAST_NOT_SUPPORTED); - zend_string *const_CODE_CAST_NOT_SUPPORTED_name = zend_string_init_interned("CODE_CAST_NOT_SUPPORTED", sizeof("CODE_CAST_NOT_SUPPORTED") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_CAST_NOT_SUPPORTED_name, &const_CODE_CAST_NOT_SUPPORTED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_CAST_NOT_SUPPORTED_name, true); - - zval const_CODE_MAKE_SEEKABLE_FAILED_value; - ZVAL_LONG(&const_CODE_MAKE_SEEKABLE_FAILED_value, STREAM_ERROR_CODE_MAKE_SEEKABLE_FAILED); - zend_string *const_CODE_MAKE_SEEKABLE_FAILED_name = zend_string_init_interned("CODE_MAKE_SEEKABLE_FAILED", sizeof("CODE_MAKE_SEEKABLE_FAILED") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_MAKE_SEEKABLE_FAILED_name, &const_CODE_MAKE_SEEKABLE_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_MAKE_SEEKABLE_FAILED_name, true); - - zval const_CODE_BUFFERED_DATA_LOST_value; - ZVAL_LONG(&const_CODE_BUFFERED_DATA_LOST_value, STREAM_ERROR_CODE_BUFFERED_DATA_LOST); - zend_string *const_CODE_BUFFERED_DATA_LOST_name = zend_string_init_interned("CODE_BUFFERED_DATA_LOST", sizeof("CODE_BUFFERED_DATA_LOST") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_BUFFERED_DATA_LOST_name, &const_CODE_BUFFERED_DATA_LOST_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_BUFFERED_DATA_LOST_name, true); - - zval const_CODE_NETWORK_SEND_FAILED_value; - ZVAL_LONG(&const_CODE_NETWORK_SEND_FAILED_value, STREAM_ERROR_CODE_NETWORK_SEND_FAILED); - zend_string *const_CODE_NETWORK_SEND_FAILED_name = zend_string_init_interned("CODE_NETWORK_SEND_FAILED", sizeof("CODE_NETWORK_SEND_FAILED") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_NETWORK_SEND_FAILED_name, &const_CODE_NETWORK_SEND_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_NETWORK_SEND_FAILED_name, true); - - zval const_CODE_NETWORK_RECV_FAILED_value; - ZVAL_LONG(&const_CODE_NETWORK_RECV_FAILED_value, STREAM_ERROR_CODE_NETWORK_RECV_FAILED); - zend_string *const_CODE_NETWORK_RECV_FAILED_name = zend_string_init_interned("CODE_NETWORK_RECV_FAILED", sizeof("CODE_NETWORK_RECV_FAILED") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_NETWORK_RECV_FAILED_name, &const_CODE_NETWORK_RECV_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_NETWORK_RECV_FAILED_name, true); - - zval const_CODE_SSL_NOT_SUPPORTED_value; - ZVAL_LONG(&const_CODE_SSL_NOT_SUPPORTED_value, STREAM_ERROR_CODE_SSL_NOT_SUPPORTED); - zend_string *const_CODE_SSL_NOT_SUPPORTED_name = zend_string_init_interned("CODE_SSL_NOT_SUPPORTED", sizeof("CODE_SSL_NOT_SUPPORTED") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_SSL_NOT_SUPPORTED_name, &const_CODE_SSL_NOT_SUPPORTED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_SSL_NOT_SUPPORTED_name, true); - - zval const_CODE_RESUMPTION_FAILED_value; - ZVAL_LONG(&const_CODE_RESUMPTION_FAILED_value, STREAM_ERROR_CODE_RESUMPTION_FAILED); - zend_string *const_CODE_RESUMPTION_FAILED_name = zend_string_init_interned("CODE_RESUMPTION_FAILED", sizeof("CODE_RESUMPTION_FAILED") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_RESUMPTION_FAILED_name, &const_CODE_RESUMPTION_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_RESUMPTION_FAILED_name, true); - - zval const_CODE_SOCKET_PATH_TOO_LONG_value; - ZVAL_LONG(&const_CODE_SOCKET_PATH_TOO_LONG_value, STREAM_ERROR_CODE_SOCKET_PATH_TOO_LONG); - zend_string *const_CODE_SOCKET_PATH_TOO_LONG_name = zend_string_init_interned("CODE_SOCKET_PATH_TOO_LONG", sizeof("CODE_SOCKET_PATH_TOO_LONG") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_SOCKET_PATH_TOO_LONG_name, &const_CODE_SOCKET_PATH_TOO_LONG_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_SOCKET_PATH_TOO_LONG_name, true); - - zval const_CODE_OOB_NOT_SUPPORTED_value; - ZVAL_LONG(&const_CODE_OOB_NOT_SUPPORTED_value, STREAM_ERROR_CODE_OOB_NOT_SUPPORTED); - zend_string *const_CODE_OOB_NOT_SUPPORTED_name = zend_string_init_interned("CODE_OOB_NOT_SUPPORTED", sizeof("CODE_OOB_NOT_SUPPORTED") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_OOB_NOT_SUPPORTED_name, &const_CODE_OOB_NOT_SUPPORTED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_OOB_NOT_SUPPORTED_name, true); - - zval const_CODE_PROTOCOL_ERROR_value; - ZVAL_LONG(&const_CODE_PROTOCOL_ERROR_value, STREAM_ERROR_CODE_PROTOCOL_ERROR); - zend_string *const_CODE_PROTOCOL_ERROR_name = zend_string_init_interned("CODE_PROTOCOL_ERROR", sizeof("CODE_PROTOCOL_ERROR") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_PROTOCOL_ERROR_name, &const_CODE_PROTOCOL_ERROR_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_PROTOCOL_ERROR_name, true); - - zval const_CODE_INVALID_URL_value; - ZVAL_LONG(&const_CODE_INVALID_URL_value, STREAM_ERROR_CODE_INVALID_URL); - zend_string *const_CODE_INVALID_URL_name = zend_string_init_interned("CODE_INVALID_URL", sizeof("CODE_INVALID_URL") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_INVALID_URL_name, &const_CODE_INVALID_URL_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_INVALID_URL_name, true); - - zval const_CODE_INVALID_RESPONSE_value; - ZVAL_LONG(&const_CODE_INVALID_RESPONSE_value, STREAM_ERROR_CODE_INVALID_RESPONSE); - zend_string *const_CODE_INVALID_RESPONSE_name = zend_string_init_interned("CODE_INVALID_RESPONSE", sizeof("CODE_INVALID_RESPONSE") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_INVALID_RESPONSE_name, &const_CODE_INVALID_RESPONSE_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_INVALID_RESPONSE_name, true); - - zval const_CODE_INVALID_HEADER_value; - ZVAL_LONG(&const_CODE_INVALID_HEADER_value, STREAM_ERROR_CODE_INVALID_HEADER); - zend_string *const_CODE_INVALID_HEADER_name = zend_string_init_interned("CODE_INVALID_HEADER", sizeof("CODE_INVALID_HEADER") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_INVALID_HEADER_name, &const_CODE_INVALID_HEADER_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_INVALID_HEADER_name, true); - - zval const_CODE_INVALID_PARAM_value; - ZVAL_LONG(&const_CODE_INVALID_PARAM_value, STREAM_ERROR_CODE_INVALID_PARAM); - zend_string *const_CODE_INVALID_PARAM_name = zend_string_init_interned("CODE_INVALID_PARAM", sizeof("CODE_INVALID_PARAM") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_INVALID_PARAM_name, &const_CODE_INVALID_PARAM_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_INVALID_PARAM_name, true); - - zval const_CODE_REDIRECT_LIMIT_value; - ZVAL_LONG(&const_CODE_REDIRECT_LIMIT_value, STREAM_ERROR_CODE_REDIRECT_LIMIT); - zend_string *const_CODE_REDIRECT_LIMIT_name = zend_string_init_interned("CODE_REDIRECT_LIMIT", sizeof("CODE_REDIRECT_LIMIT") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_REDIRECT_LIMIT_name, &const_CODE_REDIRECT_LIMIT_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_REDIRECT_LIMIT_name, true); - - zval const_CODE_AUTH_FAILED_value; - ZVAL_LONG(&const_CODE_AUTH_FAILED_value, STREAM_ERROR_CODE_AUTH_FAILED); - zend_string *const_CODE_AUTH_FAILED_name = zend_string_init_interned("CODE_AUTH_FAILED", sizeof("CODE_AUTH_FAILED") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_AUTH_FAILED_name, &const_CODE_AUTH_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_AUTH_FAILED_name, true); - - zval const_CODE_ARCHIVING_FAILED_value; - ZVAL_LONG(&const_CODE_ARCHIVING_FAILED_value, STREAM_ERROR_CODE_ARCHIVING_FAILED); - zend_string *const_CODE_ARCHIVING_FAILED_name = zend_string_init_interned("CODE_ARCHIVING_FAILED", sizeof("CODE_ARCHIVING_FAILED") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_ARCHIVING_FAILED_name, &const_CODE_ARCHIVING_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_ARCHIVING_FAILED_name, true); - - zval const_CODE_ENCODING_FAILED_value; - ZVAL_LONG(&const_CODE_ENCODING_FAILED_value, STREAM_ERROR_CODE_ENCODING_FAILED); - zend_string *const_CODE_ENCODING_FAILED_name = zend_string_init_interned("CODE_ENCODING_FAILED", sizeof("CODE_ENCODING_FAILED") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_ENCODING_FAILED_name, &const_CODE_ENCODING_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_ENCODING_FAILED_name, true); - - zval const_CODE_DECODING_FAILED_value; - ZVAL_LONG(&const_CODE_DECODING_FAILED_value, STREAM_ERROR_CODE_DECODING_FAILED); - zend_string *const_CODE_DECODING_FAILED_name = zend_string_init_interned("CODE_DECODING_FAILED", sizeof("CODE_DECODING_FAILED") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_DECODING_FAILED_name, &const_CODE_DECODING_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_DECODING_FAILED_name, true); - - zval const_CODE_INVALID_FORMAT_value; - ZVAL_LONG(&const_CODE_INVALID_FORMAT_value, STREAM_ERROR_CODE_INVALID_FORMAT); - zend_string *const_CODE_INVALID_FORMAT_name = zend_string_init_interned("CODE_INVALID_FORMAT", sizeof("CODE_INVALID_FORMAT") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_INVALID_FORMAT_name, &const_CODE_INVALID_FORMAT_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_INVALID_FORMAT_name, true); - - zval const_CODE_ALLOCATION_FAILED_value; - ZVAL_LONG(&const_CODE_ALLOCATION_FAILED_value, STREAM_ERROR_CODE_ALLOCATION_FAILED); - zend_string *const_CODE_ALLOCATION_FAILED_name = zend_string_init_interned("CODE_ALLOCATION_FAILED", sizeof("CODE_ALLOCATION_FAILED") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_ALLOCATION_FAILED_name, &const_CODE_ALLOCATION_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_ALLOCATION_FAILED_name, true); - - zval const_CODE_TEMPORARY_FILE_FAILED_value; - ZVAL_LONG(&const_CODE_TEMPORARY_FILE_FAILED_value, STREAM_ERROR_CODE_TEMPORARY_FILE_FAILED); - zend_string *const_CODE_TEMPORARY_FILE_FAILED_name = zend_string_init_interned("CODE_TEMPORARY_FILE_FAILED", sizeof("CODE_TEMPORARY_FILE_FAILED") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_TEMPORARY_FILE_FAILED_name, &const_CODE_TEMPORARY_FILE_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_TEMPORARY_FILE_FAILED_name, true); - - zval const_CODE_LOCK_FAILED_value; - ZVAL_LONG(&const_CODE_LOCK_FAILED_value, STREAM_ERROR_CODE_LOCK_FAILED); - zend_string *const_CODE_LOCK_FAILED_name = zend_string_init_interned("CODE_LOCK_FAILED", sizeof("CODE_LOCK_FAILED") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_LOCK_FAILED_name, &const_CODE_LOCK_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_LOCK_FAILED_name, true); - - zval const_CODE_LOCK_NOT_SUPPORTED_value; - ZVAL_LONG(&const_CODE_LOCK_NOT_SUPPORTED_value, STREAM_ERROR_CODE_LOCK_NOT_SUPPORTED); - zend_string *const_CODE_LOCK_NOT_SUPPORTED_name = zend_string_init_interned("CODE_LOCK_NOT_SUPPORTED", sizeof("CODE_LOCK_NOT_SUPPORTED") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_LOCK_NOT_SUPPORTED_name, &const_CODE_LOCK_NOT_SUPPORTED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_LOCK_NOT_SUPPORTED_name, true); - - zval const_CODE_USERSPACE_NOT_IMPLEMENTED_value; - ZVAL_LONG(&const_CODE_USERSPACE_NOT_IMPLEMENTED_value, STREAM_ERROR_CODE_USERSPACE_NOT_IMPLEMENTED); - zend_string *const_CODE_USERSPACE_NOT_IMPLEMENTED_name = zend_string_init_interned("CODE_USERSPACE_NOT_IMPLEMENTED", sizeof("CODE_USERSPACE_NOT_IMPLEMENTED") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_USERSPACE_NOT_IMPLEMENTED_name, &const_CODE_USERSPACE_NOT_IMPLEMENTED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_USERSPACE_NOT_IMPLEMENTED_name, true); - - zval const_CODE_USERSPACE_INVALID_RETURN_value; - ZVAL_LONG(&const_CODE_USERSPACE_INVALID_RETURN_value, STREAM_ERROR_CODE_USERSPACE_INVALID_RETURN); - zend_string *const_CODE_USERSPACE_INVALID_RETURN_name = zend_string_init_interned("CODE_USERSPACE_INVALID_RETURN", sizeof("CODE_USERSPACE_INVALID_RETURN") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_USERSPACE_INVALID_RETURN_name, &const_CODE_USERSPACE_INVALID_RETURN_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_USERSPACE_INVALID_RETURN_name, true); - - zval const_CODE_USERSPACE_CALL_FAILED_value; - ZVAL_LONG(&const_CODE_USERSPACE_CALL_FAILED_value, STREAM_ERROR_CODE_USERSPACE_CALL_FAILED); - zend_string *const_CODE_USERSPACE_CALL_FAILED_name = zend_string_init_interned("CODE_USERSPACE_CALL_FAILED", sizeof("CODE_USERSPACE_CALL_FAILED") - 1, true); - zend_declare_typed_class_constant(class_entry, const_CODE_USERSPACE_CALL_FAILED_name, &const_CODE_USERSPACE_CALL_FAILED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(const_CODE_USERSPACE_CALL_FAILED_name, true); - zval property_code_default_value; ZVAL_UNDEF(&property_code_default_value); - zend_declare_typed_property(class_entry, ZSTR_KNOWN(ZEND_STR_CODE), &property_code_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string *property_code_class_StreamErrorCode = zend_string_init("StreamErrorCode", sizeof("StreamErrorCode")-1, 1); + zend_declare_typed_property(class_entry, ZSTR_KNOWN(ZEND_STR_CODE), &property_code_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_CLASS(property_code_class_StreamErrorCode, 0, 0)); zval property_message_default_value; ZVAL_UNDEF(&property_message_default_value); From b5d3c8f87afbe7b00b7452afd0b38ef0d92236b8 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Sun, 29 Mar 2026 18:36:07 +0200 Subject: [PATCH 65/68] stream: use error code non backed enums with c headers --- build/gen_stub.php | 38 ++- ext/phar/dirstream.c | 54 ++-- ext/phar/stream.c | 82 +++---- ext/standard/ftp_fopen_wrapper.c | 52 ++-- ext/standard/http_fopen_wrapper.c | 36 +-- ext/standard/php_fopen_wrapper.c | 20 +- ...stream_errors_exception_mode_terminal.phpt | 2 +- .../stream_errors_mix_modes_storage.phpt | 16 +- main/streams/cast.c | 8 +- main/streams/filter.c | 2 +- main/streams/memory.c | 16 +- main/streams/php_stream_errors.h | 232 ++++++------------ main/streams/plain_wrapper.c | 50 ++-- main/streams/stream_errors.c | 223 +++++------------ main/streams/stream_errors.stub.php | 124 +++++++++- main/streams/stream_errors_arginfo.h | 159 +++++++++++- main/streams/stream_errors_decl.h | 183 ++++++++++++++ main/streams/streams.c | 26 +- main/streams/transports.c | 18 +- main/streams/userspace.c | 74 +++--- main/streams/xp_socket.c | 6 +- 21 files changed, 853 insertions(+), 568 deletions(-) create mode 100644 main/streams/stream_errors_decl.h diff --git a/build/gen_stub.php b/build/gen_stub.php index 9aac6b23e78b2..0e3caa90ba0d4 100755 --- a/build/gen_stub.php +++ b/build/gen_stub.php @@ -3378,6 +3378,7 @@ class ClassInfo { public array $funcInfos; /** @var EnumCaseInfo[] */ private readonly array $enumCaseInfos; + private readonly bool $generateCNameTable; public readonly ?string $cond; public ?int $phpVersionIdMinimumCompatibility; public readonly bool $isUndocumentable; @@ -3408,6 +3409,7 @@ public function __construct( array $propertyInfos, array $funcInfos, array $enumCaseInfos, + bool $generateCNameTable, ?string $cond, ?int $minimumPhpVersionIdCompatibility, bool $isUndocumentable @@ -3428,6 +3430,7 @@ public function __construct( $this->propertyInfos = $propertyInfos; $this->funcInfos = $funcInfos; $this->enumCaseInfos = $enumCaseInfos; + $this->generateCNameTable = $generateCNameTable; $this->cond = $cond; $this->phpVersionIdMinimumCompatibility = $minimumPhpVersionIdCompatibility; $this->isUndocumentable = $isUndocumentable; @@ -3622,30 +3625,49 @@ public function getCDeclarations(): string if ($this->type !== "enum") { return ''; } - + $code = ''; - + if ($this->cond) { $code .= "#if {$this->cond}\n"; } - + $cEnumName = 'zend_enum_' . str_replace('\\', '_', $this->name->toString()); - + $code .= "typedef enum {$cEnumName} {\n"; - + $i = 1; foreach ($this->enumCaseInfos as $case) { $cName = 'ZEND_ENUM_' . str_replace('\\', '_', $this->name->toString()) . '_' . $case->name; $code .= "\t{$cName} = {$i},\n"; $i++; } - + $code .= "} {$cEnumName};\n"; + + $caseCount = count($this->enumCaseInfos); + + if ($this->generateCNameTable && $caseCount > 0) { + $cPrefix = 'ZEND_ENUM_' . str_replace('\\', '_', $this->name->toString()); + $useGuard = $cPrefix . '_USE_NAME_TABLE'; + $code .= "\n#define {$cPrefix}_CASE_COUNT {$caseCount}\n"; + $code .= "\n#ifdef {$useGuard}\n"; + $code .= "static const char *{$cEnumName}_case_names[{$cPrefix}_CASE_COUNT + 1] = {\n"; + + foreach ($this->enumCaseInfos as $case) { + $cName = $cPrefix . '_' . $case->name; + $code .= "\t[{$cName}] = \"{$case->name}\",\n"; + } + + $code .= "};\n"; + $code .= "#endif\n"; + } + if ($this->cond) { $code .= "#endif\n"; } - + return $code; } @@ -5183,6 +5205,7 @@ function parseClass( $isStrictProperties = array_key_exists('strict-properties', $tagMap); $isNotSerializable = array_key_exists('not-serializable', $tagMap); $isUndocumentable = $isUndocumentable || array_key_exists('undocumentable', $tagMap); + $generateCNameTable = array_key_exists('c-name-table', $tagMap); foreach ($tags as $tag) { if ($tag->name === 'alias') { $alias = $tag->getValue(); @@ -5244,6 +5267,7 @@ function parseClass( $properties, $methods, $enumCases, + $generateCNameTable, $cond, $minimumPhpVersionIdCompatibility, $isUndocumentable diff --git a/ext/phar/dirstream.c b/ext/phar/dirstream.c index e364300b0b5f3..5cafde364465b 100644 --- a/ext/phar/dirstream.c +++ b/ext/phar/dirstream.c @@ -254,7 +254,7 @@ php_stream *phar_wrapper_open_dir(php_stream_wrapper *wrapper, const char *path, phar_archive_data *phar; if ((resource = phar_parse_url(wrapper, context, path, mode, options)) == NULL) { - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_INVALID_URL, + php_stream_wrapper_log_warn(wrapper, context, options, InvalidUrl, "phar url \"%s\" is unknown", path); return NULL; } @@ -262,21 +262,21 @@ php_stream *phar_wrapper_open_dir(php_stream_wrapper *wrapper, const char *path, /* we must have at the very least phar://alias.phar/ */ if (!resource->scheme || !resource->host || !resource->path) { if (resource->host && !resource->path) { - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_INVALID_PATH, + php_stream_wrapper_log_warn(wrapper, context, options, InvalidPath, "phar error: no directory in \"%s\", must have at least phar://%s/ for root directory (always use full path to a new phar)", path, ZSTR_VAL(resource->host)); php_url_free(resource); return NULL; } php_url_free(resource); - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_INVALID_URL, + php_stream_wrapper_log_warn(wrapper, context, options, InvalidUrl, "phar error: invalid url \"%s\", must have at least phar://%s/", path, path); return NULL; } if (!zend_string_equals_literal_ci(resource->scheme, "phar")) { php_url_free(resource); - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_PROTOCOL_UNSUPPORTED, + php_stream_wrapper_log_warn(wrapper, context, options, ProtocolUnsupported, "phar error: not a phar url \"%s\"", path); return NULL; } @@ -285,10 +285,10 @@ php_stream *phar_wrapper_open_dir(php_stream_wrapper *wrapper, const char *path, if (FAILURE == phar_get_archive(&phar, ZSTR_VAL(resource->host), ZSTR_LEN(resource->host), NULL, 0, &error)) { if (error) { - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_NOT_FOUND, "%s", error); + php_stream_wrapper_log_warn(wrapper, context, options, NotFound, "%s", error); efree(error); } else { - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_NOT_FOUND, + php_stream_wrapper_log_warn(wrapper, context, options, NotFound, "phar file \"%s\" is unknown", ZSTR_VAL(resource->host)); } php_url_free(resource); @@ -359,7 +359,7 @@ int phar_wrapper_mkdir(php_stream_wrapper *wrapper, const char *url_from, int mo /* pre-readonly check, we need to know if this is a data phar */ if (FAILURE == phar_split_fname(url_from, strlen(url_from), &arch, &arch_len, NULL, NULL, 2, 2)) { - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_NOT_FOUND, + php_stream_wrapper_log_warn(wrapper, context, options, NotFound, "phar error: cannot create directory \"%s\", no phar archive specified", url_from); return 0; } @@ -371,7 +371,7 @@ int phar_wrapper_mkdir(php_stream_wrapper *wrapper, const char *url_from, int mo efree(arch); if (PHAR_G(readonly) && (!phar || !phar->is_data)) { - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_READONLY, + php_stream_wrapper_log_warn(wrapper, context, options, Readonly, "phar error: cannot create directory \"%s\", write operations disabled", url_from); return 0; } @@ -383,20 +383,20 @@ int phar_wrapper_mkdir(php_stream_wrapper *wrapper, const char *url_from, int mo /* we must have at the very least phar://alias.phar/internalfile.php */ if (!resource->scheme || !resource->host || !resource->path) { php_url_free(resource); - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_INVALID_URL, + php_stream_wrapper_log_warn(wrapper, context, options, InvalidUrl, "phar error: invalid url \"%s\"", url_from); return 0; } if (!zend_string_equals_literal_ci(resource->scheme, "phar")) { php_url_free(resource); - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_PROTOCOL_UNSUPPORTED, + php_stream_wrapper_log_warn(wrapper, context, options, ProtocolUnsupported, "phar error: not a phar stream url \"%s\"", url_from); return 0; } if (FAILURE == phar_get_archive(&phar, ZSTR_VAL(resource->host), ZSTR_LEN(resource->host), NULL, 0, &error)) { - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_MKDIR_FAILED, + php_stream_wrapper_log_warn(wrapper, context, options, MkdirFailed, "phar error: cannot create directory \"%s\" in phar \"%s\", error retrieving phar information: %s", ZSTR_VAL(resource->path) + 1, ZSTR_VAL(resource->host), error); efree(error); @@ -410,7 +410,7 @@ int phar_wrapper_mkdir(php_stream_wrapper *wrapper, const char *url_from, int mo zend_string_efree(e->filename); efree(e); } - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_ALREADY_EXISTS, + php_stream_wrapper_log_warn(wrapper, context, options, AlreadyExists, "phar error: cannot create directory \"%s\" in phar \"%s\", directory already exists", ZSTR_VAL(resource->path)+1, ZSTR_VAL(resource->host)); php_url_free(resource); @@ -418,7 +418,7 @@ int phar_wrapper_mkdir(php_stream_wrapper *wrapper, const char *url_from, int mo } if (error) { - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_MKDIR_FAILED, + php_stream_wrapper_log_warn(wrapper, context, options, MkdirFailed, "phar error: cannot create directory \"%s\" in phar \"%s\", %s", ZSTR_VAL(resource->path)+1, ZSTR_VAL(resource->host), error); efree(error); @@ -428,7 +428,7 @@ int phar_wrapper_mkdir(php_stream_wrapper *wrapper, const char *url_from, int mo if (phar_get_entry_info_dir(phar, ZSTR_VAL(resource->path) + 1, ZSTR_LEN(resource->path) - 1, 0, &error, true)) { /* entry exists as a file */ - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_ALREADY_EXISTS, + php_stream_wrapper_log_warn(wrapper, context, options, AlreadyExists, "phar error: cannot create directory \"%s\" in phar \"%s\", file already exists", ZSTR_VAL(resource->path)+1, ZSTR_VAL(resource->host)); php_url_free(resource); @@ -436,7 +436,7 @@ int phar_wrapper_mkdir(php_stream_wrapper *wrapper, const char *url_from, int mo } if (error) { - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_MKDIR_FAILED, + php_stream_wrapper_log_warn(wrapper, context, options, MkdirFailed, "phar error: cannot create directory \"%s\" in phar \"%s\", %s", ZSTR_VAL(resource->path)+1, ZSTR_VAL(resource->host), error); efree(error); @@ -467,7 +467,7 @@ int phar_wrapper_mkdir(php_stream_wrapper *wrapper, const char *url_from, int mo entry.old_flags = PHAR_ENT_PERM_DEF_DIR; if (NULL == zend_hash_add_mem(&phar->manifest, entry.filename, &entry, sizeof(phar_entry_info))) { - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_MKDIR_FAILED, + php_stream_wrapper_log_warn(wrapper, context, options, MkdirFailed, "phar error: cannot create directory \"%s\" in phar \"%s\", adding to manifest failed", ZSTR_VAL(entry.filename), phar->fname); zend_string_efree(entry.filename); @@ -477,7 +477,7 @@ int phar_wrapper_mkdir(php_stream_wrapper *wrapper, const char *url_from, int mo phar_flush(phar, &error); if (error) { - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_MKDIR_FAILED, + php_stream_wrapper_log_warn(wrapper, context, options, MkdirFailed, "phar error: cannot create directory \"%s\" in phar \"%s\", %s", ZSTR_VAL(entry.filename), phar->fname, error); zend_hash_del(&phar->manifest, entry.filename); @@ -503,7 +503,7 @@ int phar_wrapper_rmdir(php_stream_wrapper *wrapper, const char *url, int options /* pre-readonly check, we need to know if this is a data phar */ if (FAILURE == phar_split_fname(url, strlen(url), &arch, &arch_len, NULL, NULL, 2, 2)) { - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_NOT_FOUND, + php_stream_wrapper_log_warn(wrapper, context, options, NotFound, "phar error: cannot remove directory \"%s\", no phar archive specified, or phar archive does not exist", url); return 0; } @@ -515,7 +515,7 @@ int phar_wrapper_rmdir(php_stream_wrapper *wrapper, const char *url, int options efree(arch); if (PHAR_G(readonly) && (!phar || !phar->is_data)) { - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_READONLY, + php_stream_wrapper_log_warn(wrapper, context, options, Readonly, "phar error: cannot rmdir directory \"%s\", write operations disabled", url); return 0; } @@ -527,20 +527,20 @@ int phar_wrapper_rmdir(php_stream_wrapper *wrapper, const char *url, int options /* we must have at the very least phar://alias.phar/internalfile.php */ if (!resource->scheme || !resource->host || !resource->path) { php_url_free(resource); - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_INVALID_URL, + php_stream_wrapper_log_warn(wrapper, context, options, InvalidUrl, "phar error: invalid url \"%s\"", url); return 0; } if (!zend_string_equals_literal_ci(resource->scheme, "phar")) { php_url_free(resource); - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_PROTOCOL_UNSUPPORTED, + php_stream_wrapper_log_warn(wrapper, context, options, ProtocolUnsupported, "phar error: not a phar stream url \"%s\"", url); return 0; } if (FAILURE == phar_get_archive(&phar, ZSTR_VAL(resource->host), ZSTR_LEN(resource->host), NULL, 0, &error)) { - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_RMDIR_FAILED, + php_stream_wrapper_log_warn(wrapper, context, options, RmdirFailed, "phar error: cannot remove directory \"%s\" in phar \"%s\", error retrieving phar information: %s", ZSTR_VAL(resource->path)+1, ZSTR_VAL(resource->host), error); efree(error); @@ -552,12 +552,12 @@ int phar_wrapper_rmdir(php_stream_wrapper *wrapper, const char *url, int options if (!(entry = phar_get_entry_info_dir(phar, ZSTR_VAL(resource->path) + 1, path_len, 2, &error, true))) { if (error) { - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_RMDIR_FAILED, + php_stream_wrapper_log_warn(wrapper, context, options, RmdirFailed, "phar error: cannot remove directory \"%s\" in phar \"%s\", %s", ZSTR_VAL(resource->path)+1, ZSTR_VAL(resource->host), error); efree(error); } else { - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_NOT_FOUND, + php_stream_wrapper_log_warn(wrapper, context, options, NotFound, "phar error: cannot remove directory \"%s\" in phar \"%s\", directory does not exist", ZSTR_VAL(resource->path)+1, ZSTR_VAL(resource->host)); } @@ -573,7 +573,7 @@ int phar_wrapper_rmdir(php_stream_wrapper *wrapper, const char *url, int options zend_string_starts_with_cstr(str_key, ZSTR_VAL(resource->path)+1, path_len) && IS_SLASH(ZSTR_VAL(str_key)[path_len]) ) { - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_RMDIR_FAILED, + php_stream_wrapper_log_warn(wrapper, context, options, RmdirFailed, "phar error: Directory not empty"); if (entry->is_temp_dir) { zend_string_efree(entry->filename); @@ -590,7 +590,7 @@ int phar_wrapper_rmdir(php_stream_wrapper *wrapper, const char *url, int options zend_string_starts_with_cstr(str_key, ZSTR_VAL(resource->path)+1, path_len) && IS_SLASH(ZSTR_VAL(str_key)[path_len]) ) { - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_RMDIR_FAILED, + php_stream_wrapper_log_warn(wrapper, context, options, RmdirFailed, "phar error: Directory not empty"); if (entry->is_temp_dir) { zend_string_efree(entry->filename); @@ -612,7 +612,7 @@ int phar_wrapper_rmdir(php_stream_wrapper *wrapper, const char *url, int options phar_flush(phar, &error); if (error) { - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_RMDIR_FAILED, + php_stream_wrapper_log_warn(wrapper, context, options, RmdirFailed, "phar error: cannot remove directory \"%s\" in phar \"%s\", %s", ZSTR_VAL(entry->filename), phar->fname, error); php_url_free(resource); diff --git a/ext/phar/stream.c b/ext/phar/stream.c index df993de3e6d6d..15d9f1f5b1c5f 100644 --- a/ext/phar/stream.c +++ b/ext/phar/stream.c @@ -69,7 +69,7 @@ php_url* phar_parse_url(php_stream_wrapper *wrapper, php_stream_context *context } if (mode[0] == 'a') { if (!(options & PHP_STREAM_URL_STAT_QUIET)) { - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_MODE_NOT_SUPPORTED, + php_stream_wrapper_log_warn(wrapper, context, options, ModeNotSupported, "phar error: open mode append not supported"); } return NULL; @@ -77,12 +77,12 @@ php_url* phar_parse_url(php_stream_wrapper *wrapper, php_stream_context *context if (phar_split_fname(filename, strlen(filename), &arch, &arch_len, &entry, &entry_len, 2, (mode[0] == 'w' ? 2 : 0)) == FAILURE) { if (!(options & PHP_STREAM_URL_STAT_QUIET)) { if (arch && !entry) { - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_INVALID_PATH, + php_stream_wrapper_log_warn(wrapper, context, options, InvalidPath, "phar error: no directory in \"%s\", must have at least phar://%s/ for root directory (always use full path to a new phar)", filename, arch); arch = NULL; } else { - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_INVALID_URL, + php_stream_wrapper_log_warn(wrapper, context, options, InvalidUrl, "phar error: invalid url or non-existent phar \"%s\"", filename); } } @@ -116,7 +116,7 @@ php_url* phar_parse_url(php_stream_wrapper *wrapper, php_stream_context *context } if (PHAR_G(readonly) && (!pphar || !pphar->is_data)) { if (!(options & PHP_STREAM_URL_STAT_QUIET)) { - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_READONLY, + php_stream_wrapper_log_warn(wrapper, context, options, Readonly, "phar error: write operations disabled by the php.ini setting phar.readonly"); } php_url_free(resource); @@ -126,7 +126,7 @@ php_url* phar_parse_url(php_stream_wrapper *wrapper, php_stream_context *context { if (error) { if (!(options & PHP_STREAM_URL_STAT_QUIET)) { - php_stream_wrapper_log_warn(wrapper, NULL, options, STREAM_ERROR_CODE_OPEN_FAILED, "%s", error); + php_stream_wrapper_log_warn(wrapper, NULL, options, OpenFailed, "%s", error); } efree(error); } @@ -137,7 +137,7 @@ php_url* phar_parse_url(php_stream_wrapper *wrapper, php_stream_context *context if (error) { spprintf(&error, 0, "Cannot open cached phar '%s' as writeable, copy on write failed", ZSTR_VAL(resource->host)); if (!(options & PHP_STREAM_URL_STAT_QUIET)) { - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_OPEN_FAILED, "%s", error); + php_stream_wrapper_log_warn(wrapper, context, options, OpenFailed, "%s", error); } efree(error); } @@ -149,7 +149,7 @@ php_url* phar_parse_url(php_stream_wrapper *wrapper, php_stream_context *context { if (error) { if (!(options & PHP_STREAM_URL_STAT_QUIET)) { - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_NOT_FOUND, "%s", error); + php_stream_wrapper_log_warn(wrapper, context, options, NotFound, "%s", error); } efree(error); } @@ -181,14 +181,14 @@ static php_stream * phar_wrapper_open_url(php_stream_wrapper *wrapper, const cha /* we must have at the very least phar://alias.phar/internalfile.php */ if (!resource->scheme || !resource->host || !resource->path) { php_url_free(resource); - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_INVALID_URL, + php_stream_wrapper_log_warn(wrapper, context, options, InvalidUrl, "phar error: invalid url \"%s\"", path); return NULL; } if (!zend_string_equals_literal_ci(resource->scheme, "phar")) { php_url_free(resource); - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_PROTOCOL_UNSUPPORTED, + php_stream_wrapper_log_warn(wrapper, context, options, ProtocolUnsupported, "phar error: not a phar stream url \"%s\"", path); return NULL; } @@ -200,10 +200,10 @@ static php_stream * phar_wrapper_open_url(php_stream_wrapper *wrapper, const cha if (mode[0] == 'w' || (mode[0] == 'r' && mode[1] == '+')) { if (NULL == (idata = phar_get_or_create_entry_data(ZSTR_VAL(resource->host), ZSTR_LEN(resource->host), internal_file, strlen(internal_file), mode, 0, &error, true, time(NULL)))) { if (error) { - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_CREATE_FAILED, "%s", error); + php_stream_wrapper_log_warn(wrapper, context, options, CreateFailed, "%s", error); efree(error); } else { - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_CREATE_FAILED, + php_stream_wrapper_log_warn(wrapper, context, options, CreateFailed, "phar error: file \"%s\" could not be created in phar \"%s\"", internal_file, ZSTR_VAL(resource->host)); } efree(internal_file); @@ -244,7 +244,7 @@ static php_stream * phar_wrapper_open_url(php_stream_wrapper *wrapper, const cha if (!*internal_file && (options & STREAM_OPEN_FOR_INCLUDE)) { /* retrieve the stub */ if (FAILURE == phar_get_archive(&phar, ZSTR_VAL(resource->host), ZSTR_LEN(resource->host), NULL, 0, NULL)) { - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_INVALID_FORMAT, + php_stream_wrapper_log_warn(wrapper, context, options, InvalidFormat, "file %s is not a valid phar archive", ZSTR_VAL(resource->host)); efree(internal_file); php_url_free(resource); @@ -265,7 +265,7 @@ static php_stream * phar_wrapper_open_url(php_stream_wrapper *wrapper, const cha if (stream == NULL) { stream = phar_open_archive_fp(phar); if (UNEXPECTED(!stream)) { - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_OPEN_FAILED, + php_stream_wrapper_log_warn(wrapper, context, options, OpenFailed, "phar error: could not reopen phar \"%s\"", ZSTR_VAL(resource->host)); efree(internal_file); php_url_free(resource); @@ -303,10 +303,10 @@ static php_stream * phar_wrapper_open_url(php_stream_wrapper *wrapper, const cha if ((FAILURE == phar_get_entry_data(&idata, ZSTR_VAL(resource->host), ZSTR_LEN(resource->host), internal_file, strlen(internal_file), "r", 0, &error, false)) || !idata) { idata_error: if (error) { - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_NOT_FOUND, "%s", error); + php_stream_wrapper_log_warn(wrapper, context, options, NotFound, "%s", error); efree(error); } else { - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_NOT_FOUND, + php_stream_wrapper_log_warn(wrapper, context, options, NotFound, "phar error: \"%s\" is not a file in phar \"%s\"", internal_file, ZSTR_VAL(resource->host)); } efree(internal_file); @@ -325,7 +325,7 @@ static php_stream * phar_wrapper_open_url(php_stream_wrapper *wrapper, const cha /* check length, crc32 */ if (!idata->internal_file->is_crc_checked && phar_postprocess_file(idata, idata->internal_file->crc32, &error, 2) != SUCCESS) { - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_ARCHIVING_FAILED, "%s", error); + php_stream_wrapper_log_warn(wrapper, context, options, ArchivingFailed, "%s", error); efree(error); phar_entry_delref(idata); efree(internal_file); @@ -456,7 +456,7 @@ static ssize_t phar_stream_write(php_stream *stream, const char *buf, size_t cou php_stream_seek(data->fp, data->position + data->zero, SEEK_SET); if (count != php_stream_write(data->fp, buf, count)) { - php_stream_warn(stream, STREAM_ERROR_CODE_WRITE_FAILED, + php_stream_warn(stream, WriteFailed, "phar error: Could not write %zu characters to \"%s\" in phar \"%s\"", count, ZSTR_VAL(data->internal_file->filename), data->phar->fname); return -1; @@ -485,7 +485,7 @@ static int phar_stream_flush(php_stream *stream) /* {{{ */ data->internal_file->timestamp = time(0); ret = phar_flush(data->phar, &error); if (error) { - php_stream_warn(stream, STREAM_ERROR_CODE_FLUSH_FAILED, "%s", error); + php_stream_warn(stream, FlushFailed, "%s", error); efree(error); } return ret; @@ -678,7 +678,7 @@ static int phar_wrapper_unlink(php_stream_wrapper *wrapper, const char *url, int phar_archive_data *pphar; if ((resource = phar_parse_url(wrapper, context, url, "rb", options)) == NULL) { - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_UNLINK_FAILED, + php_stream_wrapper_log_warn(wrapper, context, options, UnlinkFailed, "phar error: unlink failed"); return 0; } @@ -686,14 +686,14 @@ static int phar_wrapper_unlink(php_stream_wrapper *wrapper, const char *url, int /* we must have at the very least phar://alias.phar/internalfile.php */ if (!resource->scheme || !resource->host || !resource->path) { php_url_free(resource); - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_INVALID_URL, + php_stream_wrapper_log_warn(wrapper, context, options, InvalidUrl, "phar error: invalid url \"%s\"", url); return 0; } if (!zend_string_equals_literal_ci(resource->scheme, "phar")) { php_url_free(resource); - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_PROTOCOL_UNSUPPORTED, + php_stream_wrapper_log_warn(wrapper, context, options, ProtocolUnsupported, "phar error: not a phar stream url \"%s\"", url); return 0; } @@ -703,7 +703,7 @@ static int phar_wrapper_unlink(php_stream_wrapper *wrapper, const char *url, int pphar = zend_hash_find_ptr(&(PHAR_G(phar_fname_map)), resource->host); if (PHAR_G(readonly) && (!pphar || !pphar->is_data)) { php_url_free(resource); - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_READONLY, + php_stream_wrapper_log_warn(wrapper, context, options, Readonly, "phar error: write operations disabled by the php.ini setting phar.readonly"); return 0; } @@ -714,11 +714,11 @@ static int phar_wrapper_unlink(php_stream_wrapper *wrapper, const char *url, int if (FAILURE == phar_get_entry_data(&idata, ZSTR_VAL(resource->host), ZSTR_LEN(resource->host), internal_file, internal_file_len, "r", 0, &error, true)) { /* constraints of fp refcount were not met */ if (error) { - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_UNLINK_FAILED, + php_stream_wrapper_log_warn(wrapper, context, options, UnlinkFailed, "unlink of \"%s\" failed: %s", url, error); efree(error); } else { - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_NOT_FOUND, + php_stream_wrapper_log_warn(wrapper, context, options, NotFound, "unlink of \"%s\" failed, file does not exist", url); } efree(internal_file); @@ -730,7 +730,7 @@ static int phar_wrapper_unlink(php_stream_wrapper *wrapper, const char *url, int } if (idata->internal_file->fp_refcount > 1) { /* more than just our fp resource is open for this file */ - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_UNLINK_FAILED, + php_stream_wrapper_log_warn(wrapper, context, options, UnlinkFailed, "phar error: \"%s\" in phar \"%s\", has open file pointers, cannot unlink", internal_file, ZSTR_VAL(resource->host)); efree(internal_file); @@ -742,7 +742,7 @@ static int phar_wrapper_unlink(php_stream_wrapper *wrapper, const char *url, int efree(internal_file); phar_entry_remove(idata, &error); if (error) { - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_UNLINK_FAILED, "%s", error); + php_stream_wrapper_log_warn(wrapper, context, options, UnlinkFailed, "%s", error); efree(error); } return 1; @@ -761,7 +761,7 @@ static int phar_wrapper_rename(php_stream_wrapper *wrapper, const char *url_from error = NULL; if ((resource_from = phar_parse_url(wrapper, context, url_from, "wb", options|PHP_STREAM_URL_STAT_QUIET)) == NULL) { - php_stream_wrapper_warn(wrapper, context, options, STREAM_ERROR_CODE_INVALID_URL, + php_stream_wrapper_warn(wrapper, context, options, InvalidUrl, "phar error: cannot rename \"%s\" to \"%s\": invalid or non-writable url \"%s\"", url_from, url_to, url_from); return 0; @@ -774,14 +774,14 @@ static int phar_wrapper_rename(php_stream_wrapper *wrapper, const char *url_from } if (PHAR_G(readonly) && (!pfrom || !pfrom->is_data)) { php_url_free(resource_from); - php_stream_wrapper_warn(wrapper, context, options, STREAM_ERROR_CODE_READONLY, + php_stream_wrapper_warn(wrapper, context, options, Readonly, "phar error: Write operations disabled by the php.ini setting phar.readonly"); return 0; } if ((resource_to = phar_parse_url(wrapper, context, url_to, "wb", options|PHP_STREAM_URL_STAT_QUIET)) == NULL) { php_url_free(resource_from); - php_stream_wrapper_warn(wrapper, context, options, STREAM_ERROR_CODE_INVALID_URL, + php_stream_wrapper_warn(wrapper, context, options, InvalidUrl, "phar error: cannot rename \"%s\" to \"%s\": invalid or non-writable url \"%s\"", url_from, url_to, url_to); return 0; @@ -795,7 +795,7 @@ static int phar_wrapper_rename(php_stream_wrapper *wrapper, const char *url_from if (PHAR_G(readonly) && (!pto || !pto->is_data)) { php_url_free(resource_from); php_url_free(resource_to); - php_stream_wrapper_warn(wrapper, context, options, STREAM_ERROR_CODE_READONLY, + php_stream_wrapper_warn(wrapper, context, options, Readonly, "phar error: Write operations disabled by the php.ini setting phar.readonly"); return 0; } @@ -803,7 +803,7 @@ static int phar_wrapper_rename(php_stream_wrapper *wrapper, const char *url_from if (!zend_string_equals(resource_from->host, resource_to->host)) { php_url_free(resource_from); php_url_free(resource_to); - php_stream_wrapper_warn(wrapper, context, options, STREAM_ERROR_CODE_RENAME_FAILED, + php_stream_wrapper_warn(wrapper, context, options, RenameFailed, "phar error: cannot rename \"%s\" to \"%s\", not within the same phar archive", url_from, url_to); return 0; @@ -813,7 +813,7 @@ static int phar_wrapper_rename(php_stream_wrapper *wrapper, const char *url_from if (!resource_from->scheme || !resource_from->host || !resource_from->path) { php_url_free(resource_from); php_url_free(resource_to); - php_stream_wrapper_warn(wrapper, context, options, STREAM_ERROR_CODE_INVALID_URL, + php_stream_wrapper_warn(wrapper, context, options, InvalidUrl, "phar error: cannot rename \"%s\" to \"%s\": invalid url \"%s\"", url_from, url_to, url_from); return 0; @@ -822,7 +822,7 @@ static int phar_wrapper_rename(php_stream_wrapper *wrapper, const char *url_from if (!resource_to->scheme || !resource_to->host || !resource_to->path) { php_url_free(resource_from); php_url_free(resource_to); - php_stream_wrapper_warn(wrapper, context, options, STREAM_ERROR_CODE_INVALID_URL, + php_stream_wrapper_warn(wrapper, context, options, InvalidUrl, "phar error: cannot rename \"%s\" to \"%s\": invalid url \"%s\"", url_from, url_to, url_to); return 0; @@ -831,7 +831,7 @@ static int phar_wrapper_rename(php_stream_wrapper *wrapper, const char *url_from if (!zend_string_equals_literal_ci(resource_from->scheme, "phar")) { php_url_free(resource_from); php_url_free(resource_to); - php_stream_wrapper_warn(wrapper, context, options, STREAM_ERROR_CODE_PROTOCOL_UNSUPPORTED, + php_stream_wrapper_warn(wrapper, context, options, ProtocolUnsupported, "phar error: cannot rename \"%s\" to \"%s\": not a phar stream url \"%s\"", url_from, url_to, url_from); return 0; @@ -840,7 +840,7 @@ static int phar_wrapper_rename(php_stream_wrapper *wrapper, const char *url_from if (!zend_string_equals_literal_ci(resource_to->scheme, "phar")) { php_url_free(resource_from); php_url_free(resource_to); - php_stream_wrapper_warn(wrapper, context, options, STREAM_ERROR_CODE_PROTOCOL_UNSUPPORTED, + php_stream_wrapper_warn(wrapper, context, options, ProtocolUnsupported, "phar error: cannot rename \"%s\" to \"%s\": not a phar stream url \"%s\"", url_from, url_to, url_to); return 0; @@ -849,7 +849,7 @@ static int phar_wrapper_rename(php_stream_wrapper *wrapper, const char *url_from if (SUCCESS != phar_get_archive(&phar, ZSTR_VAL(resource_from->host), ZSTR_LEN(resource_from->host), NULL, 0, &error)) { php_url_free(resource_from); php_url_free(resource_to); - php_stream_wrapper_warn(wrapper, context, options, STREAM_ERROR_CODE_RENAME_FAILED, + php_stream_wrapper_warn(wrapper, context, options, RenameFailed, "phar error: cannot rename \"%s\" to \"%s\": %s", url_from, url_to, error); efree(error); return 0; @@ -858,7 +858,7 @@ static int phar_wrapper_rename(php_stream_wrapper *wrapper, const char *url_from if (phar->is_persistent && FAILURE == phar_copy_on_write(&phar)) { php_url_free(resource_from); php_url_free(resource_to); - php_stream_wrapper_warn(wrapper, context, options, STREAM_ERROR_CODE_RENAME_FAILED, + php_stream_wrapper_warn(wrapper, context, options, RenameFailed, "phar error: cannot rename \"%s\" to \"%s\": could not make cached phar writeable", url_from, url_to); return 0; @@ -871,7 +871,7 @@ static int phar_wrapper_rename(php_stream_wrapper *wrapper, const char *url_from if (entry->is_deleted) { php_url_free(resource_from); php_url_free(resource_to); - php_stream_wrapper_warn(wrapper, context, options, STREAM_ERROR_CODE_NOT_FOUND, + php_stream_wrapper_warn(wrapper, context, options, NotFound, "phar error: cannot rename \"%s\" to \"%s\" from extracted phar archive, source has been deleted", url_from, url_to); return 0; @@ -893,7 +893,7 @@ static int phar_wrapper_rename(php_stream_wrapper *wrapper, const char *url_from if (FAILURE == phar_copy_entry_fp(source, entry, &error)) { php_url_free(resource_from); php_url_free(resource_to); - php_stream_wrapper_warn(wrapper, context, options, STREAM_ERROR_CODE_RENAME_FAILED, + php_stream_wrapper_warn(wrapper, context, options, RenameFailed, "phar error: cannot rename \"%s\" to \"%s\": %s", url_from, url_to, error); efree(error); zend_hash_del(&phar->manifest, entry->filename); @@ -908,7 +908,7 @@ static int phar_wrapper_rename(php_stream_wrapper *wrapper, const char *url_from /* file does not exist */ php_url_free(resource_from); php_url_free(resource_to); - php_stream_wrapper_warn(wrapper, context, options, STREAM_ERROR_CODE_NOT_FOUND, + php_stream_wrapper_warn(wrapper, context, options, NotFound, "phar error: cannot rename \"%s\" to \"%s\" from extracted phar archive, source does not exist", url_from, url_to); return 0; @@ -989,7 +989,7 @@ static int phar_wrapper_rename(php_stream_wrapper *wrapper, const char *url_from if (error) { php_url_free(resource_from); php_url_free(resource_to); - php_stream_wrapper_warn(wrapper, context, options, STREAM_ERROR_CODE_RENAME_FAILED, + php_stream_wrapper_warn(wrapper, context, options, RenameFailed, "phar error: cannot rename \"%s\" to \"%s\": %s", url_from, url_to, error); efree(error); return 0; diff --git a/ext/standard/ftp_fopen_wrapper.c b/ext/standard/ftp_fopen_wrapper.c index 49352ae4a4cbe..73d58d083e77a 100644 --- a/ext/standard/ftp_fopen_wrapper.c +++ b/ext/standard/ftp_fopen_wrapper.c @@ -109,7 +109,7 @@ static int php_stream_ftp_stream_close(php_stream_wrapper *wrapper, php_stream * result = GET_FTP_RESULT(controlstream); if (result != 226 && result != 250) { php_stream_wrapper_warn(wrapper, PHP_STREAM_CONTEXT(stream), REPORT_ERRORS, - STREAM_ERROR_CODE_PROTOCOL_ERROR, + ProtocolError, "FTP server error %d:%s", result, tmp_line); ret = EOF; } @@ -188,7 +188,7 @@ static php_stream *php_ftp_fopen_connect(php_stream_wrapper *wrapper, const char /* get the response */ result = GET_FTP_RESULT(stream); if (result != 334) { - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_SSL_NOT_SUPPORTED, + php_stream_wrapper_log_warn(wrapper, context, options, SslNotSupported, "Server doesn't support FTPS."); goto connect_errexit; } else { @@ -208,7 +208,7 @@ static php_stream *php_ftp_fopen_connect(php_stream_wrapper *wrapper, const char if (php_stream_xport_crypto_setup(stream, STREAM_CRYPTO_METHOD_SSLv23_CLIENT, NULL) < 0 || php_stream_xport_crypto_enable(stream, 1) < 0) { - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_SSL_NOT_SUPPORTED, + php_stream_wrapper_log_warn(wrapper, context, options, SslNotSupported, "Unable to activate SSL mode"); php_stream_close(stream); stream = NULL; @@ -240,7 +240,7 @@ static php_stream *php_ftp_fopen_connect(php_stream_wrapper *wrapper, const char unsigned char *s = (unsigned char *) val, *e = (unsigned char *) s + val_len; \ while (s < e) { \ if (iscntrl(*s)) { \ - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_AUTH_FAILED, err_msg, val); \ + php_stream_wrapper_log_warn(wrapper, context, options, AuthFailed, err_msg, val); \ goto connect_errexit; \ } \ s++; \ @@ -437,7 +437,7 @@ php_stream * php_stream_url_wrap_ftp(php_stream_wrapper *wrapper, const char *pa } if (strpbrk(mode, "wa+")) { if (read_write) { - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_MODE_NOT_SUPPORTED, + php_stream_wrapper_log_warn(wrapper, context, options, ModeNotSupported, "FTP does not support simultaneous read/write connections"); return NULL; } @@ -449,7 +449,7 @@ php_stream * php_stream_url_wrap_ftp(php_stream_wrapper *wrapper, const char *pa } if (!read_write) { /* No mode specified? */ - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_INVALID_MODE, + php_stream_wrapper_log_warn(wrapper, context, options, InvalidMode, "Unknown file open mode"); return NULL; } @@ -461,7 +461,7 @@ php_stream * php_stream_url_wrap_ftp(php_stream_wrapper *wrapper, const char *pa return php_stream_url_wrap_http(wrapper, path, mode, options, opened_path, context STREAMS_CC); } else { /* ftp proxy is read-only */ - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_MODE_NOT_SUPPORTED, + php_stream_wrapper_log_warn(wrapper, context, options, ModeNotSupported, "FTP proxy may only be used in read mode"); return NULL; } @@ -514,7 +514,7 @@ php_stream * php_stream_url_wrap_ftp(php_stream_wrapper *wrapper, const char *pa goto errexit; } } else { - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_ALREADY_EXISTS, + php_stream_wrapper_log_warn(wrapper, context, options, AlreadyExists, "Remote file already exists and overwrite context option not specified"); errno = EEXIST; goto errexit; @@ -539,7 +539,7 @@ php_stream * php_stream_url_wrap_ftp(php_stream_wrapper *wrapper, const char *pa php_stream_printf(stream, "REST " ZEND_LONG_FMT "\r\n", Z_LVAL_P(tmpzval)); result = GET_FTP_RESULT(stream); if (result < 300 || result > 399) { - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_RESUMPTION_FAILED, + php_stream_wrapper_log_warn(wrapper, context, options, ResumptionFailed, "Unable to resume from offset " ZEND_LONG_FMT, Z_LVAL_P(tmpzval)); goto errexit; } @@ -585,7 +585,7 @@ php_stream * php_stream_url_wrap_ftp(php_stream_wrapper *wrapper, const char *pa STREAM_CRYPTO_METHOD_SSLv23_CLIENT, NULL) < 0 || php_stream_xport_crypto_enable(datastream, 1) < 0)) { - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_SSL_NOT_SUPPORTED, + php_stream_wrapper_log_warn(wrapper, context, options, SslNotSupported, "Unable to activate SSL mode"); php_stream_close(datastream); datastream = NULL; @@ -608,11 +608,11 @@ php_stream * php_stream_url_wrap_ftp(php_stream_wrapper *wrapper, const char *pa php_stream_close(stream); } if (tmp_line[0] != '\0') - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_PROTOCOL_ERROR, + php_stream_wrapper_log_warn(wrapper, context, options, ProtocolError, "FTP server reports %s", tmp_line); if (error_message) { - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_NETWORK_SEND_FAILED, + php_stream_wrapper_log_warn(wrapper, context, options, NetworkSendFailed, "Failed to set up data channel: %s", ZSTR_VAL(error_message)); zend_string_release(error_message); } @@ -758,7 +758,7 @@ static php_stream * php_stream_ftp_opendir(php_stream_wrapper *wrapper, const ch STREAM_CRYPTO_METHOD_SSLv23_CLIENT, NULL) < 0 || php_stream_xport_crypto_enable(datastream, 1) < 0)) { - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_SSL_NOT_SUPPORTED, + php_stream_wrapper_log_warn(wrapper, context, options, SslNotSupported, "Unable to activate SSL mode"); php_stream_close(datastream); datastream = NULL; @@ -783,7 +783,7 @@ static php_stream * php_stream_ftp_opendir(php_stream_wrapper *wrapper, const ch php_stream_close(stream); } if (tmp_line[0] != '\0') { - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_PROTOCOL_ERROR, + php_stream_wrapper_log_warn(wrapper, context, options, ProtocolError, "FTP server reports %s", tmp_line); } return NULL; @@ -923,7 +923,7 @@ static int php_stream_ftp_unlink(php_stream_wrapper *wrapper, const char *url, i stream = php_ftp_fopen_connect(wrapper, url, "r", 0, NULL, context, NULL, &resource, NULL, NULL); if (!stream) { if (options & REPORT_ERRORS) { - php_stream_wrapper_warn(wrapper, context, options, STREAM_ERROR_CODE_AUTH_FAILED, + php_stream_wrapper_warn(wrapper, context, options, AuthFailed, "Unable to connect to %s", url); } goto unlink_errexit; @@ -931,7 +931,7 @@ static int php_stream_ftp_unlink(php_stream_wrapper *wrapper, const char *url, i if (resource->path == NULL) { if (options & REPORT_ERRORS) { - php_stream_wrapper_warn(wrapper, context, options, STREAM_ERROR_CODE_INVALID_PATH, + php_stream_wrapper_warn(wrapper, context, options, InvalidPath, "Invalid path provided in %s", url); } goto unlink_errexit; @@ -943,7 +943,7 @@ static int php_stream_ftp_unlink(php_stream_wrapper *wrapper, const char *url, i result = GET_FTP_RESULT(stream); if (result < 200 || result > 299) { if (options & REPORT_ERRORS) { - php_stream_wrapper_warn(wrapper, context, options, STREAM_ERROR_CODE_UNLINK_FAILED, + php_stream_wrapper_warn(wrapper, context, options, UnlinkFailed, "Error Deleting file: %s", tmp_line); } goto unlink_errexit; @@ -1008,7 +1008,7 @@ static int php_stream_ftp_rename(php_stream_wrapper *wrapper, const char *url_fr stream = php_ftp_fopen_connect(wrapper, url_from, "r", 0, NULL, context, NULL, NULL, NULL, NULL); if (!stream) { if (options & REPORT_ERRORS) { - php_stream_wrapper_warn(wrapper, context, options, STREAM_ERROR_CODE_AUTH_FAILED, + php_stream_wrapper_warn(wrapper, context, options, AuthFailed, "Unable to connect to %s", ZSTR_VAL(resource_from->host)); } goto rename_errexit; @@ -1020,7 +1020,7 @@ static int php_stream_ftp_rename(php_stream_wrapper *wrapper, const char *url_fr result = GET_FTP_RESULT(stream); if (result < 300 || result > 399) { if (options & REPORT_ERRORS) { - php_stream_wrapper_warn(wrapper, context, options, STREAM_ERROR_CODE_RENAME_FAILED, + php_stream_wrapper_warn(wrapper, context, options, RenameFailed, "Error Renaming file: %s", tmp_line); } goto rename_errexit; @@ -1032,7 +1032,7 @@ static int php_stream_ftp_rename(php_stream_wrapper *wrapper, const char *url_fr result = GET_FTP_RESULT(stream); if (result < 200 || result > 299) { if (options & REPORT_ERRORS) { - php_stream_wrapper_warn(wrapper, context, options, STREAM_ERROR_CODE_RENAME_FAILED, + php_stream_wrapper_warn(wrapper, context, options, RenameFailed, "Error Renaming file: %s", tmp_line); } goto rename_errexit; @@ -1066,7 +1066,7 @@ static int php_stream_ftp_mkdir(php_stream_wrapper *wrapper, const char *url, in stream = php_ftp_fopen_connect(wrapper, url, "r", 0, NULL, context, NULL, &resource, NULL, NULL); if (!stream) { if (options & REPORT_ERRORS) { - php_stream_wrapper_warn(wrapper, context, options, STREAM_ERROR_CODE_AUTH_FAILED, + php_stream_wrapper_warn(wrapper, context, options, AuthFailed, "Unable to connect to %s", url); } goto mkdir_errexit; @@ -1074,7 +1074,7 @@ static int php_stream_ftp_mkdir(php_stream_wrapper *wrapper, const char *url, in if (resource->path == NULL) { if (options & REPORT_ERRORS) { - php_stream_wrapper_warn(wrapper, context, options, STREAM_ERROR_CODE_INVALID_PATH, + php_stream_wrapper_warn(wrapper, context, options, InvalidPath, "Invalid path provided in %s", url); } goto mkdir_errexit; @@ -1116,7 +1116,7 @@ static int php_stream_ftp_mkdir(php_stream_wrapper *wrapper, const char *url, in result = GET_FTP_RESULT(stream); if (result < 200 || result > 299) { if (options & REPORT_ERRORS) { - php_stream_wrapper_warn(wrapper, context, options, STREAM_ERROR_CODE_MKDIR_FAILED, + php_stream_wrapper_warn(wrapper, context, options, MkdirFailed, "%s", tmp_line); } break; @@ -1161,7 +1161,7 @@ static int php_stream_ftp_rmdir(php_stream_wrapper *wrapper, const char *url, in stream = php_ftp_fopen_connect(wrapper, url, "r", 0, NULL, context, NULL, &resource, NULL, NULL); if (!stream) { if (options & REPORT_ERRORS) { - php_stream_wrapper_warn(wrapper, context, options, STREAM_ERROR_CODE_AUTH_FAILED, + php_stream_wrapper_warn(wrapper, context, options, AuthFailed, "Unable to connect to %s", url); } goto rmdir_errexit; @@ -1169,7 +1169,7 @@ static int php_stream_ftp_rmdir(php_stream_wrapper *wrapper, const char *url, in if (resource->path == NULL) { if (options & REPORT_ERRORS) { - php_stream_wrapper_warn(wrapper, context, options, STREAM_ERROR_CODE_INVALID_PATH, + php_stream_wrapper_warn(wrapper, context, options, InvalidPath, "Invalid path provided in %s", url); } goto rmdir_errexit; @@ -1180,7 +1180,7 @@ static int php_stream_ftp_rmdir(php_stream_wrapper *wrapper, const char *url, in if (result < 200 || result > 299) { if (options & REPORT_ERRORS) { - php_stream_wrapper_warn(wrapper, context, options, STREAM_ERROR_CODE_RMDIR_FAILED, + php_stream_wrapper_warn(wrapper, context, options, RmdirFailed, "%s", tmp_line); } goto rmdir_errexit; diff --git a/ext/standard/http_fopen_wrapper.c b/ext/standard/http_fopen_wrapper.c index a15862d784e94..11b33f5020ca0 100644 --- a/ext/standard/http_fopen_wrapper.c +++ b/ext/standard/http_fopen_wrapper.c @@ -245,7 +245,7 @@ static zend_string *php_stream_http_response_headers_parse(php_stream_wrapper *w while (last_header_name < last_header_value) { if (*last_header_name == ' ' || *last_header_name == '\t') { header_info->error = true; - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_INVALID_RESPONSE, + php_stream_wrapper_log_warn(wrapper, context, options, InvalidResponse, "HTTP invalid response format (space in header name)!"); zend_string_efree(last_header_line_str); return NULL; @@ -263,7 +263,7 @@ static zend_string *php_stream_http_response_headers_parse(php_stream_wrapper *w } else { /* There is no colon which means invalid response so error. */ header_info->error = true; - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_INVALID_RESPONSE, + php_stream_wrapper_log_warn(wrapper, context, options, InvalidResponse, "HTTP invalid response format (no colon in header line)!"); zend_string_efree(last_header_line_str); return NULL; @@ -287,7 +287,7 @@ static zend_string *php_stream_http_response_headers_parse(php_stream_wrapper *w size_t last_header_value_len = strlen(last_header_value); if (last_header_value_len > HTTP_HEADER_MAX_LOCATION_SIZE) { header_info->error = true; - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_INVALID_RESPONSE, + php_stream_wrapper_log_warn(wrapper, context, options, InvalidResponse, "HTTP Location header size is over the limit of %d bytes", HTTP_HEADER_MAX_LOCATION_SIZE); zend_string_efree(last_header_line_str); @@ -388,7 +388,7 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, tmp_line[0] = '\0'; if (redirect_max < 1) { - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_REDIRECT_LIMIT, + php_stream_wrapper_log_warn(wrapper, context, options, RedirectLimit, "Redirection limit reached, aborting"); return NULL; } @@ -422,7 +422,7 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, /* Normal http request (possibly with proxy) */ if (strpbrk(mode, "awx+")) { - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_MODE_NOT_SUPPORTED, + php_stream_wrapper_log_warn(wrapper, context, options, ModeNotSupported, "HTTP wrapper does not support writeable connections"); php_uri_struct_free(resource); return NULL; @@ -452,7 +452,7 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, } if (request_fulluri && (strchr(path, '\n') != NULL || strchr(path, '\r') != NULL)) { - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_INVALID_URL, + php_stream_wrapper_log_warn(wrapper, context, options, InvalidUrl, "HTTP wrapper full URI path does not allow CR or LF characters"); php_uri_struct_free(resource); zend_string_release(transport_string); @@ -468,7 +468,7 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, #endif if (d > timeoutmax) { - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_INVALID_PARAM, + php_stream_wrapper_log_warn(wrapper, context, options, InvalidParam, "timeout must be lower than " ZEND_ULONG_FMT, (zend_ulong)timeoutmax); zend_string_release(transport_string); php_uri_struct_free(resource); @@ -499,7 +499,7 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, } if (errstr) { - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_PROTOCOL_ERROR, + php_stream_wrapper_log_warn(wrapper, context, options, ProtocolError, "%s", ZSTR_VAL(errstr)); zend_string_release_ex(errstr, 0); errstr = NULL; @@ -551,7 +551,7 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, smart_str_appendl(&header, "\r\n", sizeof("\r\n")-1); if (php_stream_write(stream, ZSTR_VAL(header.s), ZSTR_LEN(header.s)) != ZSTR_LEN(header.s)) { - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_PROTOCOL_ERROR, + php_stream_wrapper_log_warn(wrapper, context, options, ProtocolError, "Cannot connect to HTTPS server through proxy"); php_stream_close(stream); stream = NULL; @@ -575,7 +575,7 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, if (stream) { if (php_stream_xport_crypto_setup(stream, STREAM_CRYPTO_METHOD_SSLv23_CLIENT, NULL) < 0 || php_stream_xport_crypto_enable(stream, 1) < 0) { - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_SSL_NOT_SUPPORTED, + php_stream_wrapper_log_warn(wrapper, context, options, SslNotSupported, "Cannot connect to HTTPS server through proxy"); php_stream_close(stream); stream = NULL; @@ -833,7 +833,7 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, ua[ua_len] = 0; smart_str_appendl(&req_buf, ua, ua_len); } else { - php_stream_wrapper_warn_nt(wrapper, context, options, STREAM_ERROR_CODE_INVALID_HEADER, + php_stream_wrapper_warn_nt(wrapper, context, options, InvalidHeader, "Cannot construct User-agent header"); } efree(ua); @@ -873,7 +873,7 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, } if (!(have_header & HTTP_HEADER_TYPE)) { smart_str_appends(&req_buf, "Content-Type: application/x-www-form-urlencoded\r\n"); - php_stream_wrapper_notice(wrapper, context, options, STREAM_ERROR_CODE_INVALID_HEADER, + php_stream_wrapper_notice(wrapper, context, options, InvalidHeader, "Content-type not specified assuming application/x-www-form-urlencoded"); } smart_str_appends(&req_buf, "\r\n"); @@ -961,7 +961,7 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, } else { php_stream_close(stream); stream = NULL; - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_PROTOCOL_ERROR, + php_stream_wrapper_log_warn(wrapper, context, options, ProtocolError, "HTTP request failed!"); goto out; } @@ -980,7 +980,7 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, if (http_header_line[1] != '\n') { php_stream_close(stream); stream = NULL; - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_INVALID_RESPONSE, + php_stream_wrapper_log_warn(wrapper, context, options, InvalidResponse, "HTTP invalid header name (cannot start with CR character)!"); goto out; } @@ -1011,7 +1011,7 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, if (*http_header_line == ' ' || *http_header_line == '\t') { php_stream_close(stream); stream = NULL; - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_INVALID_RESPONSE, + php_stream_wrapper_log_warn(wrapper, context, options, InvalidResponse, "HTTP invalid response format (folding header at the start)!"); goto out; } @@ -1107,7 +1107,7 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, php_uri_struct_free(resource); /* check for invalid redirection URLs */ if ((resource = php_uri_parse_to_struct(uri_parser, new_path, strlen(new_path), PHP_URI_COMPONENT_READ_MODE_RAW, true)) == NULL) { - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_INVALID_URL, + php_stream_wrapper_log_warn(wrapper, context, options, InvalidUrl, "Invalid redirect URL! %s", new_path); efree(new_path); goto out; @@ -1120,7 +1120,7 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, s = (unsigned char*)ZSTR_VAL(val); e = s + ZSTR_LEN(val); \ while (s < e) { \ if (iscntrl(*s)) { \ - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_INVALID_URL, \ + php_stream_wrapper_log_warn(wrapper, context, options, InvalidUrl, \ "Invalid redirect URL! %s", new_path); \ efree(new_path); \ goto out; \ @@ -1147,7 +1147,7 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, --redirect_max, new_flags, response_header STREAMS_CC); efree(new_path); } else { - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_PROTOCOL_ERROR, + php_stream_wrapper_log_warn(wrapper, context, options, ProtocolError, "HTTP request failed! %s", tmp_line); } } diff --git a/ext/standard/php_fopen_wrapper.c b/ext/standard/php_fopen_wrapper.c index 902b0f853f4e4..8f5be5fb873db 100644 --- a/ext/standard/php_fopen_wrapper.c +++ b/ext/standard/php_fopen_wrapper.c @@ -159,7 +159,7 @@ static void php_stream_apply_filter_list(php_stream *stream, char *filterlist, i php_stream_filter_append(&stream->readfilters, temp_filter); } else { php_stream_wrapper_warn_nt(NULL, PHP_STREAM_CONTEXT(stream), REPORT_ERRORS, - STREAM_ERROR_CODE_CREATE_FAILED, + CreateFailed, "Unable to create filter (%s)", p); } } @@ -168,7 +168,7 @@ static void php_stream_apply_filter_list(php_stream *stream, char *filterlist, i php_stream_filter_append(&stream->writefilters, temp_filter); } else { php_stream_wrapper_warn_nt(NULL, PHP_STREAM_CONTEXT(stream), REPORT_ERRORS, - STREAM_ERROR_CODE_CREATE_FAILED, + CreateFailed, "Unable to create filter (%s)", p); } } @@ -224,7 +224,7 @@ static php_stream * php_stream_url_wrap_php(php_stream_wrapper *wrapper, const c if ((options & STREAM_OPEN_FOR_INCLUDE) && !PG(allow_url_include) ) { if (options & REPORT_ERRORS) { php_stream_wrapper_warn(wrapper, context, options, - STREAM_ERROR_CODE_DISABLED, + Disabled, "URL file-access is disabled in the server configuration"); } return NULL; @@ -245,7 +245,7 @@ static php_stream * php_stream_url_wrap_php(php_stream_wrapper *wrapper, const c if ((options & STREAM_OPEN_FOR_INCLUDE) && !PG(allow_url_include) ) { if (options & REPORT_ERRORS) { php_stream_wrapper_warn(wrapper, context, options, - STREAM_ERROR_CODE_DISABLED, + Disabled, "URL file-access is disabled in the server configuration"); } return NULL; @@ -306,7 +306,7 @@ static php_stream * php_stream_url_wrap_php(php_stream_wrapper *wrapper, const c if (strcmp(sapi_module.name, "cli")) { if (options & REPORT_ERRORS) { php_stream_wrapper_warn(wrapper, context, options, - STREAM_ERROR_CODE_DISABLED, + Disabled, "Direct access to file descriptors is only available from command-line PHP"); } return NULL; @@ -315,7 +315,7 @@ static php_stream * php_stream_url_wrap_php(php_stream_wrapper *wrapper, const c if ((options & STREAM_OPEN_FOR_INCLUDE) && !PG(allow_url_include) ) { if (options & REPORT_ERRORS) { php_stream_wrapper_warn(wrapper, context, options, - STREAM_ERROR_CODE_DISABLED, + Disabled, "URL file-access is disabled in the server configuration"); } return NULL; @@ -325,7 +325,7 @@ static php_stream * php_stream_url_wrap_php(php_stream_wrapper *wrapper, const c fildes_ori = ZEND_STRTOL(start, &end, 10); if (end == start || *end != '\0') { php_stream_wrapper_log_warn(wrapper, context, options, - STREAM_ERROR_CODE_INVALID_URL, + InvalidUrl, "php://fd/ stream must be specified in the form php://fd/"); return NULL; } @@ -338,7 +338,7 @@ static php_stream * php_stream_url_wrap_php(php_stream_wrapper *wrapper, const c if (fildes_ori < 0 || fildes_ori >= dtablesize) { php_stream_wrapper_log_warn(wrapper, context, options, - STREAM_ERROR_CODE_INVALID_PARAM, + InvalidParam, "The file descriptors must be non-negative numbers smaller than %d", dtablesize); return NULL; } @@ -346,7 +346,7 @@ static php_stream * php_stream_url_wrap_php(php_stream_wrapper *wrapper, const c fd = dup((int)fildes_ori); if (fd == -1) { php_stream_wrapper_log_warn(wrapper, context, options, - STREAM_ERROR_CODE_DUP_FAILED, + DupFailed, "Error duping file descriptor " ZEND_LONG_FMT "; possibly it doesn't exist: " "[%d]: %s", fildes_ori, errno, strerror(errno)); return NULL; @@ -396,7 +396,7 @@ static php_stream * php_stream_url_wrap_php(php_stream_wrapper *wrapper, const c } else { /* invalid php://thingy */ php_stream_wrapper_warn(wrapper, context, options, - STREAM_ERROR_CODE_INVALID_URL, "Invalid php:// URL specified"); + InvalidUrl, "Invalid php:// URL specified"); return NULL; } diff --git a/ext/standard/tests/streams/stream_errors_exception_mode_terminal.phpt b/ext/standard/tests/streams/stream_errors_exception_mode_terminal.phpt index d66e6d654f1df..f3aaf1153db9e 100644 --- a/ext/standard/tests/streams/stream_errors_exception_mode_terminal.phpt +++ b/ext/standard/tests/streams/stream_errors_exception_mode_terminal.phpt @@ -25,6 +25,6 @@ try { ?> --EXPECTF-- Caught: Failed to open stream: operation failed -Code: 36 +Code: 20 Wrapper: PHP Error code name: OpenFailed diff --git a/ext/standard/tests/streams/stream_errors_mix_modes_storage.phpt b/ext/standard/tests/streams/stream_errors_mix_modes_storage.phpt index 1f2ccb8300f5c..d7c8f51669300 100644 --- a/ext/standard/tests/streams/stream_errors_mix_modes_storage.phpt +++ b/ext/standard/tests/streams/stream_errors_mix_modes_storage.phpt @@ -46,9 +46,9 @@ function stream_test_errors($title, $contextOptions) { $error = stream_get_last_error(); if ($error) { echo "Error details:\n"; - echo "- Message: " . $error->message . "\n"; - echo "- Code: " . $error->code->name . " (" . $error->code->value . ")\n"; - echo "- Wrapper: " . $error->wrapperName . "\n"; + echo "- Message: $error->message\n"; + echo "- Code: " . $error->code->name . "\n"; + echo "- Wrapper: $error->wrapperName\n"; echo "- Terminating: " . ($error->terminating ? 'yes' : 'no') . "\n"; echo "- Count: " . $error->count() . "\n"; @@ -106,7 +106,7 @@ stream_test_errors('AUTO ERROR', [ ALL Error details: - Message: TestStream::stream_cast is not implemented! -- Code: NotImplemented (70) +- Code: NotImplemented - Wrapper: user-space - Terminating: yes - Count: 2 @@ -116,7 +116,7 @@ Error details: NON TERMINATING Error details: - Message: TestStream::stream_read - read 10 bytes more data than requested (8202 read, 8192 max) - excess data will be lost -- Code: UserspaceInvalidReturn (161) +- Code: UserspaceInvalidReturn - Wrapper: user-space - Terminating: no - Count: 1 @@ -125,7 +125,7 @@ Error details: TERMINATING Error details: - Message: TestStream::stream_cast is not implemented! -- Code: NotImplemented (70) +- Code: NotImplemented - Wrapper: user-space - Terminating: yes - Count: 2 @@ -136,7 +136,7 @@ AUTO EXCEPTION EXCEPTION: TestStream::stream_cast is not implemented! Error details: - Message: TestStream::stream_read - read 10 bytes more data than requested (8202 read, 8192 max) - excess data will be lost -- Code: UserspaceInvalidReturn (161) +- Code: UserspaceInvalidReturn - Wrapper: user-space - Terminating: no - Count: 1 @@ -151,7 +151,7 @@ Warning: stream_select(): TestStream::stream_cast is not implemented! in %s on l Warning: stream_select(): Cannot represent a stream of type user-space as a select()able descriptor in %s on line %d Error details: - Message: TestStream::stream_read - read 10 bytes more data than requested (8202 read, 8192 max) - excess data will be lost -- Code: UserspaceInvalidReturn (161) +- Code: UserspaceInvalidReturn - Wrapper: user-space - Terminating: no - Count: 1 diff --git a/main/streams/cast.c b/main/streams/cast.c index 3322c9d50f184..638fa28d0d859 100644 --- a/main/streams/cast.c +++ b/main/streams/cast.c @@ -258,7 +258,7 @@ PHPAPI zend_result _php_stream_cast(php_stream *stream, int castas, void **ret, b) no memory -> lets bail */ - php_stream_fatal(stream, STREAM_ERROR_CODE_CAST_FAILED, "fopencookie failed"); + php_stream_fatal(stream, CastFailed, "fopencookie failed"); return FAILURE; #endif @@ -298,7 +298,7 @@ PHPAPI zend_result _php_stream_cast(php_stream *stream, int castas, void **ret, if (php_stream_is_filtered(stream) && castas != PHP_STREAM_AS_FD_FOR_SELECT) { if (show_err) { - php_stream_warn(stream, STREAM_ERROR_CODE_CAST_NOT_SUPPORTED, + php_stream_warn(stream, CastNotSupported, "Cannot cast a filtered stream on this system"); } return FAILURE; @@ -315,7 +315,7 @@ PHPAPI zend_result _php_stream_cast(php_stream *stream, int castas, void **ret, "select()able descriptor" }; - php_stream_warn(stream, STREAM_ERROR_CODE_CAST_NOT_SUPPORTED, + php_stream_warn(stream, CastNotSupported, "Cannot represent a stream of type %s as a %s", stream->ops->label, cast_names[castas]); } @@ -331,7 +331,7 @@ PHPAPI zend_result _php_stream_cast(php_stream *stream, int castas, void **ret, * will be accessing the stream. Emit a warning so that the end-user will * know that they should try something else */ - php_stream_warn_nt(stream, STREAM_ERROR_CODE_BUFFERED_DATA_LOST, + php_stream_warn_nt(stream, BufferedDataLost, ZEND_LONG_FMT " bytes of buffered data lost during stream conversion!", (zend_long)(stream->writepos - stream->readpos)); } diff --git a/main/streams/filter.c b/main/streams/filter.c index 5c98e2c2faae3..d63be91d27054 100644 --- a/main/streams/filter.c +++ b/main/streams/filter.c @@ -343,7 +343,7 @@ PHPAPI zend_result php_stream_filter_append_ex(php_stream_filter_chain *chain, p php_stream_bucket_unlink(bucket); php_stream_bucket_delref(bucket); } - php_stream_warn(stream, STREAM_ERROR_CODE_FILTER_FAILED, + php_stream_warn(stream, FilterFailed, "Filter failed to process pre-buffered data"); return FAILURE; case PSFS_FEED_ME: diff --git a/main/streams/memory.c b/main/streams/memory.c index 1d0685f133a49..1f5580de044ac 100644 --- a/main/streams/memory.c +++ b/main/streams/memory.c @@ -365,7 +365,7 @@ static ssize_t php_stream_temp_write(php_stream *stream, const char *buf, size_t php_stream *file = php_stream_fopen_temporary_file(ts->tmpdir, "php", NULL); if (file == NULL) { php_stream_wrapper_warn(NULL, PHP_STREAM_CONTEXT(stream), REPORT_ERRORS, - STREAM_ERROR_CODE_PERMISSION_DENIED, + PermissionDenied, "Unable to create temporary file, Check permissions in temporary files directory."); return 0; } @@ -494,7 +494,7 @@ static int php_stream_temp_cast(php_stream *stream, int castas, void **ret) file = php_stream_fopen_tmpfile(); if (file == NULL) { php_stream_wrapper_warn(NULL, PHP_STREAM_CONTEXT(stream), REPORT_ERRORS, - STREAM_ERROR_CODE_PERMISSION_DENIED, "Unable to create temporary file."); + PermissionDenied, "Unable to create temporary file."); return FAILURE; } @@ -645,7 +645,7 @@ static php_stream * php_stream_url_wrap_rfc2397(php_stream_wrapper *wrapper, con if ((comma = (char *) memchr(path, ',', dlen)) == NULL) { php_stream_wrapper_log_warn(wrapper, context, options, - STREAM_ERROR_CODE_INVALID_URL, "rfc2397: no comma in URL"); + InvalidUrl, "rfc2397: no comma in URL"); return NULL; } @@ -658,7 +658,7 @@ static php_stream * php_stream_url_wrap_rfc2397(php_stream_wrapper *wrapper, con if (!semi && !sep) { php_stream_wrapper_log_warn(wrapper, context, options, - STREAM_ERROR_CODE_INVALID_URL, "rfc2397: illegal media type"); + InvalidUrl, "rfc2397: illegal media type"); return NULL; } @@ -674,7 +674,7 @@ static php_stream * php_stream_url_wrap_rfc2397(php_stream_wrapper *wrapper, con } else if (semi != path || mlen != sizeof(";base64")-1 || memcmp(path, ";base64", sizeof(";base64")-1)) { /* must be error since parameters are only allowed after mediatype */ zval_ptr_dtor(&meta); php_stream_wrapper_log_warn(wrapper, context, options, - STREAM_ERROR_CODE_INVALID_URL, "rfc2397: illegal media type"); + InvalidUrl, "rfc2397: illegal media type"); return NULL; } /* get parameters and potentially ';base64' */ @@ -688,7 +688,7 @@ static php_stream * php_stream_url_wrap_rfc2397(php_stream_wrapper *wrapper, con /* must be error since parameters are only allowed after mediatype and we have no '=' sign */ zval_ptr_dtor(&meta); php_stream_wrapper_log_warn(wrapper, context, options, - STREAM_ERROR_CODE_INVALID_PARAM, "rfc2397: illegal parameter"); + InvalidParam, "rfc2397: illegal parameter"); return NULL; } base64 = 1; @@ -709,7 +709,7 @@ static php_stream * php_stream_url_wrap_rfc2397(php_stream_wrapper *wrapper, con if (mlen) { zval_ptr_dtor(&meta); php_stream_wrapper_log_warn(wrapper, context, options, - STREAM_ERROR_CODE_INVALID_URL, "rfc2397: illegal URL"); + InvalidUrl, "rfc2397: illegal URL"); return NULL; } } else { @@ -726,7 +726,7 @@ static php_stream * php_stream_url_wrap_rfc2397(php_stream_wrapper *wrapper, con if (!base64_comma) { zval_ptr_dtor(&meta); php_stream_wrapper_log_warn(wrapper, context, options, - STREAM_ERROR_CODE_DECODING_FAILED, "rfc2397: unable to decode"); + DecodingFailed, "rfc2397: unable to decode"); return NULL; } comma = ZSTR_VAL(base64_comma); diff --git a/main/streams/php_stream_errors.h b/main/streams/php_stream_errors.h index 4d64e3905034a..7bcafa779984c 100644 --- a/main/streams/php_stream_errors.h +++ b/main/streams/php_stream_errors.h @@ -19,6 +19,7 @@ #include "php.h" #include "php_streams.h" +#include "stream_errors_decl.h" BEGIN_EXTERN_C() @@ -39,124 +40,30 @@ BEGIN_EXTERN_C() /* Operations pool size to prevent extra allocations */ #define PHP_STREAM_ERROR_OPERATION_POOL_SIZE 8 -/* Error code ranges */ -#define STREAM_ERROR_CODE_IO_START 10 -#define STREAM_ERROR_CODE_IO_END 30 -#define STREAM_ERROR_CODE_FILESYSTEM_START 30 -#define STREAM_ERROR_CODE_FILESYSTEM_END 70 -#define STREAM_ERROR_CODE_WRAPPER_START 70 -#define STREAM_ERROR_CODE_WRAPPER_END 90 -#define STREAM_ERROR_CODE_FILTER_START 90 -#define STREAM_ERROR_CODE_FILTER_END 100 -#define STREAM_ERROR_CODE_CAST_START 100 -#define STREAM_ERROR_CODE_CAST_END 110 -#define STREAM_ERROR_CODE_NETWORK_START 110 -#define STREAM_ERROR_CODE_NETWORK_END 130 -#define STREAM_ERROR_CODE_ENCODING_START 130 -#define STREAM_ERROR_CODE_ENCODING_END 140 -#define STREAM_ERROR_CODE_RESOURCE_START 140 -#define STREAM_ERROR_CODE_RESOURCE_END 150 -#define STREAM_ERROR_CODE_LOCK_START 150 -#define STREAM_ERROR_CODE_LOCK_END 160 -#define STREAM_ERROR_CODE_USERSPACE_START 160 -#define STREAM_ERROR_CODE_USERSPACE_END 170 - -/* X-macro defining all error codes */ -#define PHP_STREAM_ERROR_CODES(V) \ - /* General errors */ \ - V(NONE, None, 0) \ - V(GENERIC, Generic, 1) \ - /* I/O operation errors (10-29) */ \ - V(READ_FAILED, ReadFailed, 10) \ - V(WRITE_FAILED, WriteFailed, 11) \ - V(SEEK_FAILED, SeekFailed, 12) \ - V(SEEK_NOT_SUPPORTED, SeekNotSupported, 13) \ - V(FLUSH_FAILED, FlushFailed, 14) \ - V(TRUNCATE_FAILED, TruncateFailed, 15) \ - V(CONNECT_FAILED, ConnectFailed, 16) \ - V(BIND_FAILED, BindFailed, 17) \ - V(LISTEN_FAILED, ListenFailed, 18) \ - V(NOT_WRITABLE, NotWritable, 19) \ - V(NOT_READABLE, NotReadable, 20) \ - /* File system operations (30-69) */ \ - V(DISABLED, Disabled, 30) \ - V(NOT_FOUND, NotFound, 31) \ - V(PERMISSION_DENIED, PermissionDenied, 32) \ - V(ALREADY_EXISTS, AlreadyExists, 33) \ - V(INVALID_PATH, InvalidPath, 34) \ - V(PATH_TOO_LONG, PathTooLong, 35) \ - V(OPEN_FAILED, OpenFailed, 36) \ - V(CREATE_FAILED, CreateFailed, 37) \ - V(DUP_FAILED, DupFailed, 38) \ - V(UNLINK_FAILED, UnlinkFailed, 39) \ - V(RENAME_FAILED, RenameFailed, 40) \ - V(MKDIR_FAILED, MkdirFailed, 41) \ - V(RMDIR_FAILED, RmdirFailed, 42) \ - V(STAT_FAILED, StatFailed, 43) \ - V(META_FAILED, MetaFailed, 44) \ - V(CHMOD_FAILED, ChmodFailed, 45) \ - V(CHOWN_FAILED, ChownFailed, 46) \ - V(COPY_FAILED, CopyFailed, 47) \ - V(TOUCH_FAILED, TouchFailed, 48) \ - V(INVALID_MODE, InvalidMode, 49) \ - V(INVALID_META, InvalidMeta, 50) \ - V(MODE_NOT_SUPPORTED, ModeNotSupported, 51) \ - V(READONLY, Readonly, 52) \ - V(RECURSION_DETECTED, RecursionDetected, 53) \ - /* Wrapper/protocol operations (70-89) */ \ - V(NOT_IMPLEMENTED, NotImplemented, 70) \ - V(NO_OPENER, NoOpener, 71) \ - V(PERSISTENT_NOT_SUPPORTED, PersistentNotSupported, 72) \ - V(WRAPPER_NOT_FOUND, WrapperNotFound, 73) \ - V(WRAPPER_DISABLED, WrapperDisabled, 74) \ - V(PROTOCOL_UNSUPPORTED, ProtocolUnsupported, 75) \ - V(WRAPPER_REGISTRATION_FAILED, WrapperRegistrationFailed, 76) \ - V(WRAPPER_UNREGISTRATION_FAILED, WrapperUnregistrationFailed, 77) \ - V(WRAPPER_RESTORATION_FAILED, WrapperRestorationFailed, 78) \ - /* Filter operations (90-99) */ \ - V(FILTER_NOT_FOUND, FilterNotFound, 90) \ - V(FILTER_FAILED, FilterFailed, 91) \ - /* Cast/conversion operations (100-109) */ \ - V(CAST_FAILED, CastFailed, 100) \ - V(CAST_NOT_SUPPORTED, CastNotSupported, 101) \ - V(MAKE_SEEKABLE_FAILED, MakeSeekableFailed, 102) \ - V(BUFFERED_DATA_LOST, BufferedDataLost, 103) \ - /* Network/socket operations (110-129) */ \ - V(NETWORK_SEND_FAILED, NetworkSendFailed, 110) \ - V(NETWORK_RECV_FAILED, NetworkRecvFailed, 111) \ - V(SSL_NOT_SUPPORTED, SslNotSupported, 112) \ - V(RESUMPTION_FAILED, ResumptionFailed, 113) \ - V(SOCKET_PATH_TOO_LONG, SocketPathTooLong, 114) \ - V(OOB_NOT_SUPPORTED, OobNotSupported, 115) \ - V(PROTOCOL_ERROR, ProtocolError, 116) \ - V(INVALID_URL, InvalidUrl, 117) \ - V(INVALID_RESPONSE, InvalidResponse, 118) \ - V(INVALID_HEADER, InvalidHeader, 119) \ - V(INVALID_PARAM, InvalidParam, 120) \ - V(REDIRECT_LIMIT, RedirectLimit, 121) \ - V(AUTH_FAILED, AuthFailed, 122) \ - /* Encoding/decoding/archiving operations (130-139) */ \ - V(ARCHIVING_FAILED, ArchivingFailed, 130) \ - V(ENCODING_FAILED, EncodingFailed, 131) \ - V(DECODING_FAILED, DecodingFailed, 132) \ - V(INVALID_FORMAT, InvalidFormat, 133) \ - /* Resource/allocation operations (140-149) */ \ - V(ALLOCATION_FAILED, AllocationFailed, 140) \ - V(TEMPORARY_FILE_FAILED, TemporaryFileFailed, 141) \ - /* Locking operations (150-159) */ \ - V(LOCK_FAILED, LockFailed, 150) \ - V(LOCK_NOT_SUPPORTED, LockNotSupported, 151) \ - /* Userspace stream operations (160-169) */ \ - V(USERSPACE_NOT_IMPLEMENTED, UserspaceNotImplemented, 160) \ - V(USERSPACE_INVALID_RETURN, UserspaceInvalidReturn, 161) \ - V(USERSPACE_CALL_FAILED, UserspaceCallFailed, 162) - -/* Generate C enum for internal use */ -typedef enum _StreamErrorCode { -#define V(uc_name, name, val) STREAM_ERROR_CODE_##uc_name = val, - PHP_STREAM_ERROR_CODES(V) -#undef V -} StreamErrorCode; +/* Shorthand for error code enum values */ +#define PHP_STREAM_EC(name) ZEND_ENUM_StreamErrorCode_##name + +/* Error code range boundaries (case_id based, ranges are [start, end)) */ +#define STREAM_EC_IO_START PHP_STREAM_EC(ReadFailed) +#define STREAM_EC_IO_END PHP_STREAM_EC(Disabled) +#define STREAM_EC_FS_START PHP_STREAM_EC(Disabled) +#define STREAM_EC_FS_END PHP_STREAM_EC(NotImplemented) +#define STREAM_EC_WRAPPER_START PHP_STREAM_EC(NotImplemented) +#define STREAM_EC_WRAPPER_END PHP_STREAM_EC(FilterNotFound) +#define STREAM_EC_FILTER_START PHP_STREAM_EC(FilterNotFound) +#define STREAM_EC_FILTER_END PHP_STREAM_EC(CastFailed) +#define STREAM_EC_CAST_START PHP_STREAM_EC(CastFailed) +#define STREAM_EC_CAST_END PHP_STREAM_EC(NetworkSendFailed) +#define STREAM_EC_NETWORK_START PHP_STREAM_EC(NetworkSendFailed) +#define STREAM_EC_NETWORK_END PHP_STREAM_EC(ArchivingFailed) +#define STREAM_EC_ENCODING_START PHP_STREAM_EC(ArchivingFailed) +#define STREAM_EC_ENCODING_END PHP_STREAM_EC(AllocationFailed) +#define STREAM_EC_RESOURCE_START PHP_STREAM_EC(AllocationFailed) +#define STREAM_EC_RESOURCE_END PHP_STREAM_EC(LockFailed) +#define STREAM_EC_LOCK_START PHP_STREAM_EC(LockFailed) +#define STREAM_EC_LOCK_END PHP_STREAM_EC(UserspaceNotImplemented) +#define STREAM_EC_USERSPACE_START PHP_STREAM_EC(UserspaceNotImplemented) +#define STREAM_EC_USERSPACE_END (PHP_STREAM_EC(UserspaceCallFailed) + 1) /* Wrapper name for PHP errors */ #define PHP_STREAM_ERROR_WRAPPER_DEFAULT_NAME ":na" @@ -166,7 +73,7 @@ typedef enum _StreamErrorCode { /* Error entry in chain */ typedef struct _php_stream_error_entry { zend_string *message; - StreamErrorCode code; + zend_enum_StreamErrorCode code; char *wrapper_name; char *param; char *docref; @@ -189,15 +96,11 @@ typedef struct _php_stream_stored_error { } php_stream_stored_error; typedef struct { - /* Stack of active operations (LIFO for nesting) */ php_stream_error_operation *current_operation; uint32_t operation_depth; - /* List of completed/stored operations (most recent first) */ php_stream_stored_error *stored_errors; uint32_t stored_count; - /* Pre-allocated operation pool */ php_stream_error_operation operation_pool[PHP_STREAM_ERROR_OPERATION_POOL_SIZE]; - /* Overflow operations (for deep nesting beyond pool size) */ php_stream_error_operation *overflow_operations; uint32_t overflow_capacity; } php_stream_error_state; @@ -217,96 +120,115 @@ PHPAPI void php_stream_error_create_object(zval *zv, php_stream_error_entry *ent /* Wrapper error reporting functions */ PHPAPI void php_stream_wrapper_error_with_name(const char *wrapper_name, php_stream_context *context, const char *docref, int options, int severity, - bool terminating, int code, const char *fmt, ...) ZEND_ATTRIBUTE_FORMAT(printf, 8, 9); + bool terminating, zend_enum_StreamErrorCode code, const char *fmt, ...) + ZEND_ATTRIBUTE_FORMAT(printf, 8, 9); PHPAPI void php_stream_wrapper_error(php_stream_wrapper *wrapper, php_stream_context *context, - const char *docref, int options, int severity, bool terminating, int code, const char *fmt, - ...) ZEND_ATTRIBUTE_FORMAT(printf, 8, 9); + const char *docref, int options, int severity, bool terminating, + zend_enum_StreamErrorCode code, const char *fmt, ...) + ZEND_ATTRIBUTE_FORMAT(printf, 8, 9); PHPAPI void php_stream_wrapper_error_param(php_stream_wrapper *wrapper, php_stream_context *context, - const char *docref, int options, int severity, bool terminating, int code, - const char *param, const char *fmt, ...) ZEND_ATTRIBUTE_FORMAT(printf, 9, 10); + const char *docref, int options, int severity, bool terminating, + zend_enum_StreamErrorCode code, const char *param, const char *fmt, ...) + ZEND_ATTRIBUTE_FORMAT(printf, 9, 10); PHPAPI void php_stream_wrapper_error_param2(php_stream_wrapper *wrapper, php_stream_context *context, const char *docref, int options, int severity, - bool terminating, int code, const char *param1, const char *param2, const char *fmt, ...) - ZEND_ATTRIBUTE_FORMAT(printf, 10, 11); + bool terminating, zend_enum_StreamErrorCode code, const char *param1, const char *param2, + const char *fmt, ...) ZEND_ATTRIBUTE_FORMAT(printf, 10, 11); -PHPAPI void php_stream_error(php_stream *stream, const char *docref, int severity, bool terminating, - int code, const char *fmt, ...) ZEND_ATTRIBUTE_FORMAT(printf, 6, 7); +PHPAPI void php_stream_error(php_stream *stream, const char *docref, int severity, + bool terminating, zend_enum_StreamErrorCode code, const char *fmt, ...) + ZEND_ATTRIBUTE_FORMAT(printf, 6, 7); /* Legacy wrapper error log functions */ PHPAPI void php_stream_wrapper_log_error(const php_stream_wrapper *wrapper, - php_stream_context *context, int options, int severity, bool terminating, int code, - const char *fmt, ...) ZEND_ATTRIBUTE_FORMAT(printf, 7, 8); + php_stream_context *context, int options, int severity, bool terminating, + zend_enum_StreamErrorCode code, const char *fmt, ...) + ZEND_ATTRIBUTE_FORMAT(printf, 7, 8); PHPAPI void php_stream_wrapper_log_error_param(const php_stream_wrapper *wrapper, - php_stream_context *context, int options, int severity, bool terminating, int code, - const char *param, const char *fmt, ...) ZEND_ATTRIBUTE_FORMAT(printf, 8, 9); + php_stream_context *context, int options, int severity, bool terminating, + zend_enum_StreamErrorCode code, const char *param, const char *fmt, ...) + ZEND_ATTRIBUTE_FORMAT(printf, 8, 9); PHPAPI void php_stream_display_wrapper_name_errors(const char *wrapper_name, - php_stream_context *context, int code, const char *path, const char *caption); + php_stream_context *context, zend_enum_StreamErrorCode code, const char *path, + const char *caption); PHPAPI void php_stream_display_wrapper_errors(php_stream_wrapper *wrapper, - php_stream_context *context, int code, const char *path, const char *caption); + php_stream_context *context, zend_enum_StreamErrorCode code, const char *path, + const char *caption); PHPAPI void php_stream_tidy_wrapper_name_error_log(const char *wrapper_name); PHPAPI void php_stream_tidy_wrapper_error_log(php_stream_wrapper *wrapper); -/* Convenience macros */ +/* Convenience macros - code argument is the bare case name (e.g. RenameFailed) */ #define php_stream_wrapper_warn(wrapper, context, options, code, ...) \ - php_stream_wrapper_error(wrapper, context, NULL, options, E_WARNING, true, code, __VA_ARGS__) + php_stream_wrapper_error(wrapper, context, NULL, options, E_WARNING, true, \ + PHP_STREAM_EC(code), __VA_ARGS__) #define php_stream_wrapper_warn_name(wrapper_name, context, options, code, ...) \ php_stream_wrapper_error_with_name( \ - wrapper_name, context, NULL, options, E_WARNING, true, code, __VA_ARGS__) + wrapper_name, context, NULL, options, E_WARNING, true, \ + PHP_STREAM_EC(code), __VA_ARGS__) #define php_stream_wrapper_warn_nt(wrapper, context, options, code, ...) \ - php_stream_wrapper_error(wrapper, context, NULL, options, E_WARNING, false, code, __VA_ARGS__) + php_stream_wrapper_error(wrapper, context, NULL, options, E_WARNING, false, \ + PHP_STREAM_EC(code), __VA_ARGS__) #define php_stream_wrapper_notice(wrapper, context, options, code, ...) \ - php_stream_wrapper_error(wrapper, context, NULL, options, E_NOTICE, false, code, __VA_ARGS__) + php_stream_wrapper_error(wrapper, context, NULL, options, E_NOTICE, false, \ + PHP_STREAM_EC(code), __VA_ARGS__) #define php_stream_wrapper_warn_param(wrapper, context, options, code, param, ...) \ php_stream_wrapper_error_param( \ - wrapper, context, NULL, options, E_WARNING, true, code, param, __VA_ARGS__) + wrapper, context, NULL, options, E_WARNING, true, \ + PHP_STREAM_EC(code), param, __VA_ARGS__) #define php_stream_wrapper_warn_param_nt(wrapper, context, options, code, param, ...) \ php_stream_wrapper_error_param( \ - wrapper, context, NULL, options, E_WARNING, false, code, param, __VA_ARGS__) + wrapper, context, NULL, options, E_WARNING, false, \ + PHP_STREAM_EC(code), param, __VA_ARGS__) #define php_stream_wrapper_warn_param2(wrapper, context, options, code, param1, param2, ...) \ php_stream_wrapper_error_param2( \ - wrapper, context, NULL, options, E_WARNING, true, code, param1, param2, __VA_ARGS__) + wrapper, context, NULL, options, E_WARNING, true, \ + PHP_STREAM_EC(code), param1, param2, __VA_ARGS__) #define php_stream_wrapper_warn_param2_nt(wrapper, context, options, code, param1, param2, ...) \ php_stream_wrapper_error_param2( \ - wrapper, context, NULL, options, E_WARNING, false, code, param1, param2, __VA_ARGS__) + wrapper, context, NULL, options, E_WARNING, false, \ + PHP_STREAM_EC(code), param1, param2, __VA_ARGS__) #define php_stream_warn(stream, code, ...) \ - php_stream_error(stream, NULL, E_WARNING, true, code, __VA_ARGS__) + php_stream_error(stream, NULL, E_WARNING, true, PHP_STREAM_EC(code), __VA_ARGS__) #define php_stream_warn_nt(stream, code, ...) \ - php_stream_error(stream, NULL, E_WARNING, false, code, __VA_ARGS__) + php_stream_error(stream, NULL, E_WARNING, false, PHP_STREAM_EC(code), __VA_ARGS__) #define php_stream_warn_docref(stream, docref, code, ...) \ - php_stream_error(stream, docref, E_WARNING, true, code, __VA_ARGS__) + php_stream_error(stream, docref, E_WARNING, true, PHP_STREAM_EC(code), __VA_ARGS__) #define php_stream_notice(stream, code, ...) \ - php_stream_error(stream, NULL, E_NOTICE, false, code, __VA_ARGS__) + php_stream_error(stream, NULL, E_NOTICE, false, PHP_STREAM_EC(code), __VA_ARGS__) #define php_stream_fatal(stream, code, ...) \ - php_stream_error(stream, NULL, E_ERROR, true, code, __VA_ARGS__) + php_stream_error(stream, NULL, E_ERROR, true, PHP_STREAM_EC(code), __VA_ARGS__) /* Legacy log variants */ #define php_stream_wrapper_log_warn(wrapper, context, options, code, ...) \ - php_stream_wrapper_log_error(wrapper, context, options, E_WARNING, true, code, __VA_ARGS__) + php_stream_wrapper_log_error(wrapper, context, options, E_WARNING, true, \ + PHP_STREAM_EC(code), __VA_ARGS__) #define php_stream_wrapper_log_warn_nt(wrapper, context, options, code, ...) \ - php_stream_wrapper_log_error(wrapper, context, options, E_WARNING, false, code, __VA_ARGS__) + php_stream_wrapper_log_error(wrapper, context, options, E_WARNING, false, \ + PHP_STREAM_EC(code), __VA_ARGS__) #define php_stream_wrapper_log_notice(wrapper, context, options, code, ...) \ - php_stream_wrapper_log_error(wrapper, context, options, E_NOTICE, false, code, __VA_ARGS__) + php_stream_wrapper_log_error(wrapper, context, options, E_NOTICE, false, \ + PHP_STREAM_EC(code), __VA_ARGS__) END_EXTERN_C() diff --git a/main/streams/plain_wrapper.c b/main/streams/plain_wrapper.c index c3f6128656d07..76800d222e403 100644 --- a/main/streams/plain_wrapper.c +++ b/main/streams/plain_wrapper.c @@ -394,7 +394,7 @@ static ssize_t php_stdiop_write(php_stream *stream, const char *buf, size_t coun } if (!(stream->flags & PHP_STREAM_FLAG_SUPPRESS_ERRORS)) { char errstr[256]; - php_stream_notice(stream, STREAM_ERROR_CODE_WRITE_FAILED, + php_stream_notice(stream, WriteFailed, "Write of %zu bytes failed with errno=%d %s", count, errno, php_socket_strerror_s(errno, errstr, sizeof(errstr))); } @@ -473,7 +473,7 @@ static ssize_t php_stdiop_read(php_stream *stream, char *buf, size_t count) } else { if (!(stream->flags & PHP_STREAM_FLAG_SUPPRESS_ERRORS)) { char errstr[256]; - php_stream_notice(stream, STREAM_ERROR_CODE_READ_FAILED, + php_stream_notice(stream, ReadFailed, "Read of %zu bytes failed with errno=%d %s", count, errno, php_socket_strerror_s(errno, errstr, sizeof(errstr))); } @@ -624,7 +624,7 @@ static int php_stdiop_seek(php_stream *stream, zend_off_t offset, int whence, ze if (!data->is_seekable) { php_stream_wrapper_warn(NULL, PHP_STREAM_CONTEXT(stream), REPORT_ERRORS, - STREAM_ERROR_CODE_SEEK_NOT_SUPPORTED, "Cannot seek on this stream"); + SeekNotSupported, "Cannot seek on this stream"); return -1; } @@ -1162,7 +1162,7 @@ PHPAPI php_stream *_php_stream_fopen(const char *filename, const char *mode, zen if (FAILURE == php_stream_parse_fopen_modes(mode, &open_flags)) { php_stream_wrapper_log_warn(&php_plain_files_wrapper, NULL, options, - STREAM_ERROR_CODE_INVALID_MODE, "`%s' is not a valid mode for fopen", mode); + InvalidMode, "`%s' is not a valid mode for fopen", mode); return NULL; } @@ -1316,7 +1316,7 @@ static int php_plain_files_unlink(php_stream_wrapper *wrapper, const char *url, if (options & REPORT_ERRORS) { char errstr[256]; php_stream_wrapper_warn_param(wrapper, context, options, - STREAM_ERROR_CODE_UNLINK_FAILED, url, + UnlinkFailed, url, "%s", php_socket_strerror_s(errno, errstr, sizeof(errstr))); } return 0; @@ -1388,7 +1388,7 @@ static int php_plain_files_rename(php_stream_wrapper *wrapper, const char *url_f success = 0; } php_stream_wrapper_error_param2(wrapper, context, NULL, options, E_WARNING, - !success, STREAM_ERROR_CODE_CHOWN_FAILED, url_from, url_to, + !success, PHP_STREAM_EC(ChownFailed), url_from, url_to, "%s", php_socket_strerror_s(errno, errstr, sizeof(errstr))); } @@ -1398,7 +1398,7 @@ static int php_plain_files_rename(php_stream_wrapper *wrapper, const char *url_f success = 0; } php_stream_wrapper_error_param2(wrapper, context, NULL, options, E_WARNING, - !success, STREAM_ERROR_CODE_CHOWN_FAILED, url_from, url_to, + !success, PHP_STREAM_EC(ChownFailed), url_from, url_to, "%s", php_socket_strerror_s(errno, errstr, sizeof(errstr))); } } @@ -1407,13 +1407,13 @@ static int php_plain_files_rename(php_stream_wrapper *wrapper, const char *url_f VCWD_UNLINK(url_from); } } else { - php_stream_wrapper_warn_param2_nt(wrapper, context, options, - STREAM_ERROR_CODE_STAT_FAILED, url_from, url_to, + php_stream_wrapper_warn_param2_nt(wrapper, context, options, StatFailed, + url_from, url_to, "%s", php_socket_strerror_s(errno, errstr, sizeof(errstr))); } } else { - php_stream_wrapper_warn_param2_nt(wrapper, context, options, - STREAM_ERROR_CODE_COPY_FAILED, url_from, url_to, + php_stream_wrapper_warn_param2_nt(wrapper, context, options, CopyFailed, + url_from, url_to, "%s", php_socket_strerror_s(errno, errstr, sizeof(errstr))); } # if !defined(ZTS) && !defined(TSRM_WIN32) @@ -1428,7 +1428,7 @@ static int php_plain_files_rename(php_stream_wrapper *wrapper, const char *url_f php_win32_docref2_from_error(GetLastError(), url_from, url_to); #else php_stream_wrapper_warn_param2(wrapper, context, options, - STREAM_ERROR_CODE_RENAME_FAILED, url_from, url_to, + RenameFailed, url_from, url_to, "%s", php_socket_strerror_s(errno, errstr, sizeof(errstr))); #endif return 0; @@ -1454,7 +1454,7 @@ static int php_plain_files_mkdir(php_stream_wrapper *wrapper, const char *dir, i int ret = VCWD_MKDIR(dir, (mode_t)mode); if (ret < 0 && (options & REPORT_ERRORS)) { php_stream_wrapper_warn(wrapper, context, options, - STREAM_ERROR_CODE_MKDIR_FAILED, "%s", strerror(errno)); + MkdirFailed, "%s", strerror(errno)); return 0; } @@ -1464,7 +1464,7 @@ static int php_plain_files_mkdir(php_stream_wrapper *wrapper, const char *dir, i char buf[MAXPATHLEN]; if (!expand_filepath_with_mode(dir, buf, NULL, 0, CWD_EXPAND)) { php_stream_wrapper_warn(wrapper, context, options, - STREAM_ERROR_CODE_INVALID_PATH, "Invalid path"); + InvalidPath, "Invalid path"); return 0; } @@ -1517,7 +1517,7 @@ static int php_plain_files_mkdir(php_stream_wrapper *wrapper, const char *dir, i if (ret < 0 && errno != EEXIST) { if (options & REPORT_ERRORS) { php_stream_wrapper_warn(wrapper, context, options, - STREAM_ERROR_CODE_MKDIR_FAILED, + MkdirFailed, "%s", php_socket_strerror_s(errno, errstr, sizeof(errstr))); } return 0; @@ -1539,7 +1539,7 @@ static int php_plain_files_mkdir(php_stream_wrapper *wrapper, const char *dir, i if (ret < 0) { if (options & REPORT_ERRORS) { php_stream_wrapper_warn(wrapper, context, options, - STREAM_ERROR_CODE_MKDIR_FAILED, + MkdirFailed, "%s", php_socket_strerror_s(errno, errstr, sizeof(errstr))); } return 0; @@ -1563,7 +1563,7 @@ static int php_plain_files_rmdir(php_stream_wrapper *wrapper, const char *url, i #ifdef PHP_WIN32 if (!php_win32_check_trailing_space(url, strlen(url))) { php_stream_wrapper_warn_param(wrapper, context, options, - STREAM_ERROR_CODE_NOT_FOUND, url, + NotFound, url, "%s", php_socket_strerror_s(ENOENT, errstr, sizeof(errstr))); return 0; } @@ -1571,7 +1571,7 @@ static int php_plain_files_rmdir(php_stream_wrapper *wrapper, const char *url, i if (VCWD_RMDIR(url) < 0) { php_stream_wrapper_warn_param(wrapper, context, options, - STREAM_ERROR_CODE_RMDIR_FAILED, url, + RmdirFailed, url, "%s", php_socket_strerror_s(errno, errstr, sizeof(errstr))); return 0; } @@ -1596,7 +1596,7 @@ static int php_plain_files_metadata(php_stream_wrapper *wrapper, const char *url #ifdef PHP_WIN32 if (!php_win32_check_trailing_space(url, strlen(url))) { php_stream_wrapper_warn_param(wrapper, context, REPORT_ERRORS, - STREAM_ERROR_CODE_NOT_FOUND, url, + NotFound, url, "%s", php_socket_strerror_s(ENOENT, errstr, sizeof(errstr))); return 0; } @@ -1617,7 +1617,7 @@ static int php_plain_files_metadata(php_stream_wrapper *wrapper, const char *url FILE *file = VCWD_FOPEN(url, "w"); if (file == NULL) { php_stream_wrapper_warn_param(wrapper, context, REPORT_ERRORS, - STREAM_ERROR_CODE_PERMISSION_DENIED, url, + PermissionDenied, url, "Unable to create file %s because %s", url, php_socket_strerror_s(errno, errstr, sizeof(errstr))); return 0; @@ -1633,7 +1633,7 @@ static int php_plain_files_metadata(php_stream_wrapper *wrapper, const char *url if(option == PHP_STREAM_META_OWNER_NAME) { if(php_get_uid_by_name((char *)value, &uid) != SUCCESS) { php_stream_wrapper_warn_param(wrapper, context, REPORT_ERRORS, - STREAM_ERROR_CODE_META_FAILED, url, + MetaFailed, url, "Unable to find uid for %s", (char *)value); return 0; } @@ -1647,7 +1647,7 @@ static int php_plain_files_metadata(php_stream_wrapper *wrapper, const char *url if(option == PHP_STREAM_META_GROUP_NAME) { if(php_get_gid_by_name((char *)value, &gid) != SUCCESS) { php_stream_wrapper_warn_param(wrapper, context, REPORT_ERRORS, - STREAM_ERROR_CODE_META_FAILED, url, + MetaFailed, url, "Unable to find gid for %s", (char *)value); return 0; } @@ -1667,7 +1667,7 @@ static int php_plain_files_metadata(php_stream_wrapper *wrapper, const char *url } if (ret == -1) { php_stream_wrapper_warn_param(wrapper, context, REPORT_ERRORS, - STREAM_ERROR_CODE_META_FAILED, url, + MetaFailed, url, "Operation failed: %s", php_socket_strerror_s(errno, errstr, sizeof(errstr))); return 0; } @@ -1762,7 +1762,7 @@ PHPAPI php_stream *_php_stream_fopen_with_path(const char *filename, const char if (snprintf(trypath, MAXPATHLEN, "%s%s", cwd, filename) >= MAXPATHLEN) { php_stream_wrapper_notice(NULL, NULL, REPORT_ERRORS, - STREAM_ERROR_CODE_PATH_TOO_LONG, + PathTooLong, "%s/%s path was truncated to %d", cwd, filename, MAXPATHLEN); } @@ -1819,7 +1819,7 @@ PHPAPI php_stream *_php_stream_fopen_with_path(const char *filename, const char } if (snprintf(trypath, MAXPATHLEN, "%s/%s", ptr, filename) >= MAXPATHLEN) { php_stream_wrapper_notice(NULL, NULL, REPORT_ERRORS, - STREAM_ERROR_CODE_PATH_TOO_LONG, + PathTooLong, "%s/%s path was truncated to %d", ptr, filename, MAXPATHLEN); } diff --git a/main/streams/stream_errors.c b/main/streams/stream_errors.c index 4e2b68efd82fb..76bf612221f99 100644 --- a/main/streams/stream_errors.c +++ b/main/streams/stream_errors.c @@ -14,6 +14,7 @@ +----------------------------------------------------------------------+ */ +#define ZEND_ENUM_StreamErrorCode_USE_NAME_TABLE 1 #include "php.h" #include "php_globals.h" #include "php_streams.h" @@ -30,13 +31,6 @@ static zend_class_entry *php_ce_stream_error_store; static zend_class_entry *php_ce_stream_error; static zend_class_entry *php_ce_stream_exception; -/* Lookup table for error code to case name */ -static const char *const php_stream_error_code_names[200] = { -#define V(uc_name, name, val) [val] = #name, - PHP_STREAM_ERROR_CODES(V) -#undef V -}; - /* Forward declarations */ static void php_stream_error_entry_free(php_stream_error_entry *entry); static bool php_stream_error_code_in_range(zval *this_zv, int start, int end); @@ -74,15 +68,13 @@ static int php_stream_get_error_mode(php_stream_context *context) return PHP_STREAM_ERROR_MODE_ERROR; } - /* Get enum case name */ - zend_string *case_name = Z_STR_P(zend_enum_fetch_case_name(Z_OBJ_P(option))); - - if (zend_string_equals_literal(case_name, "Error")) { - return PHP_STREAM_ERROR_MODE_ERROR; - } else if (zend_string_equals_literal(case_name, "Exception")) { - return PHP_STREAM_ERROR_MODE_EXCEPTION; - } else if (zend_string_equals_literal(case_name, "Silent")) { - return PHP_STREAM_ERROR_MODE_SILENT; + switch ((zend_enum_StreamErrorMode) zend_enum_fetch_case_id(Z_OBJ_P(option))) { + case ZEND_ENUM_StreamErrorMode_Error: + return PHP_STREAM_ERROR_MODE_ERROR; + case ZEND_ENUM_StreamErrorMode_Exception: + return PHP_STREAM_ERROR_MODE_EXCEPTION; + case ZEND_ENUM_StreamErrorMode_Silent: + return PHP_STREAM_ERROR_MODE_SILENT; } return PHP_STREAM_ERROR_MODE_ERROR; @@ -105,19 +97,17 @@ static int php_stream_get_error_store_mode(php_stream_context *context, int erro return php_stream_auto_decide_error_store_mode(error_mode); } - /* Get enum case name */ - zend_string *case_name = Z_STR_P(zend_enum_fetch_case_name(Z_OBJ_P(option))); - - if (zend_string_equals_literal(case_name, "Auto")) { - return php_stream_auto_decide_error_store_mode(error_mode); - } else if (zend_string_equals_literal(case_name, "None")) { - return PHP_STREAM_ERROR_STORE_NONE; - } else if (zend_string_equals_literal(case_name, "NonTerminating")) { - return PHP_STREAM_ERROR_STORE_NON_TERM; - } else if (zend_string_equals_literal(case_name, "Terminating")) { - return PHP_STREAM_ERROR_STORE_TERMINAL; - } else if (zend_string_equals_literal(case_name, "All")) { - return PHP_STREAM_ERROR_STORE_ALL; + switch ((zend_enum_StreamErrorStore) zend_enum_fetch_case_id(Z_OBJ_P(option))) { + case ZEND_ENUM_StreamErrorStore_Auto: + return php_stream_auto_decide_error_store_mode(error_mode); + case ZEND_ENUM_StreamErrorStore_None: + return PHP_STREAM_ERROR_STORE_NONE; + case ZEND_ENUM_StreamErrorStore_NonTerminating: + return PHP_STREAM_ERROR_STORE_NON_TERM; + case ZEND_ENUM_StreamErrorStore_Terminating: + return PHP_STREAM_ERROR_STORE_TERMINAL; + case ZEND_ENUM_StreamErrorStore_All: + return PHP_STREAM_ERROR_STORE_ALL; } return php_stream_auto_decide_error_store_mode(error_mode); @@ -137,7 +127,6 @@ static bool php_stream_has_terminating_error(php_stream_error_operation *op) return false; } -/* Helper to get operation at specific depth */ static inline php_stream_error_operation *php_stream_get_operation_at_depth(uint32_t depth) { php_stream_error_state *state = &FG(stream_error_state); @@ -151,7 +140,6 @@ static inline php_stream_error_operation *php_stream_get_operation_at_depth(uint } } -/* Helper to get parent operation */ static inline php_stream_error_operation *php_stream_get_parent_operation(void) { php_stream_error_state *state = &FG(stream_error_state); @@ -181,22 +169,18 @@ PHPAPI void php_stream_error_state_cleanup(void) { php_stream_error_state *state = &FG(stream_error_state); - /* Clear active operations */ while (state->current_operation) { php_stream_error_operation *op = state->current_operation; state->operation_depth--; state->current_operation = php_stream_get_parent_operation(); - /* Free errors */ php_stream_error_entry_free(op->first_error); - /* Reset operation */ op->first_error = NULL; op->last_error = NULL; op->error_count = 0; } - /* Clear stored errors */ php_stream_stored_error *stored = state->stored_errors; while (stored) { php_stream_stored_error *next = stored->next; @@ -209,7 +193,6 @@ PHPAPI void php_stream_error_state_cleanup(void) state->stored_count = 0; state->operation_depth = 0; - /* Free overflow operations array */ if (state->overflow_operations) { efree(state->overflow_operations); state->overflow_operations = NULL; @@ -223,7 +206,6 @@ PHPAPI php_stream_error_operation *php_stream_error_operation_begin(void) { php_stream_error_state *state = &FG(stream_error_state); - /* Check depth limit */ if (state->operation_depth >= PHP_STREAM_ERROR_MAX_DEPTH) { php_error_docref(NULL, E_WARNING, "Stream error operation depth exceeded (%u), possible infinite recursion", @@ -233,14 +215,11 @@ PHPAPI php_stream_error_operation *php_stream_error_operation_begin(void) php_stream_error_operation *op; - /* Try to use pre-allocated pool first */ if (state->operation_depth < PHP_STREAM_ERROR_OPERATION_POOL_SIZE) { op = &state->operation_pool[state->operation_depth]; } else { - /* Need overflow allocation */ uint32_t overflow_index = state->operation_depth - PHP_STREAM_ERROR_OPERATION_POOL_SIZE; - /* Grow overflow array if needed */ if (overflow_index >= state->overflow_capacity) { uint32_t new_capacity = state->overflow_capacity == 0 ? 8 : state->overflow_capacity * 2; @@ -253,19 +232,17 @@ PHPAPI php_stream_error_operation *php_stream_error_operation_begin(void) op = &state->overflow_operations[overflow_index]; } - /* Initialize operation */ op->first_error = NULL; op->last_error = NULL; op->error_count = 0; - /* Update stack state */ state->current_operation = op; state->operation_depth++; return op; } -static void php_stream_error_add(StreamErrorCode code, const char *wrapper_name, +static void php_stream_error_add(zend_enum_StreamErrorCode code, const char *wrapper_name, zend_string *message, const char *docref, char *param, int severity, bool terminating) { php_stream_error_operation *op = FG(stream_error_state).current_operation; @@ -281,7 +258,6 @@ static void php_stream_error_add(StreamErrorCode code, const char *wrapper_name, entry->terminating = terminating; entry->next = NULL; - /* Append to operation's error list */ if (op->last_error) { op->last_error->next = entry; } else { @@ -319,23 +295,18 @@ static void php_stream_throw_exception_with_errors(php_stream_error_operation *o return; } - /* Create StreamError object from error chain */ zval error_obj; php_stream_error_create_object(&error_obj, op->first_error); - /* Create exception */ zval ex; object_init_ex(&ex, php_ce_stream_exception); - /* Set message from first error */ zend_update_property_string(php_ce_stream_exception, Z_OBJ(ex), ZEND_STRL("message"), ZSTR_VAL(op->first_error->message)); - /* Set code from first error enum value */ zend_update_property_long(php_ce_stream_exception, Z_OBJ(ex), ZEND_STRL("code"), (zend_long) op->first_error->code); - /* Set the complete error object */ zend_update_property(php_ce_stream_exception, Z_OBJ(ex), ZEND_STRL("error"), &error_obj); zval_ptr_dtor(&error_obj); @@ -347,7 +318,6 @@ static void php_stream_report_errors(php_stream_context *context, php_stream_err { switch (error_mode) { case PHP_STREAM_ERROR_MODE_ERROR: { - /* Report all errors individually */ php_stream_error_entry *entry = op->first_error; while (entry) { if (entry->param) { @@ -370,27 +340,23 @@ static void php_stream_report_errors(php_stream_context *context, php_stream_err } case PHP_STREAM_ERROR_MODE_SILENT: - /* Don't report */ break; } - /* Call user error handler if set */ zval *handler = context ? php_stream_context_get_option(context, "stream", "error_handler") : NULL; if (handler) { - /* Create StreamError object from error chain */ zval error_obj; php_stream_error_create_object(&error_obj, op->first_error); - /* Call handler(error) */ php_stream_call_error_handler(handler, &error_obj); zval_ptr_dtor(&error_obj); } } -/* Error storage - move and filter */ +/* Error storage */ PHPAPI void php_stream_error_operation_end(php_stream_context *context) { @@ -401,32 +367,25 @@ PHPAPI void php_stream_error_operation_end(php_stream_context *context) return; } - /* Pop from stack */ state->operation_depth--; state->current_operation = php_stream_get_parent_operation(); - /* Process errors if we have any */ if (op->error_count > 0) { if (context == NULL) { context = FG(default_context); } - /* Get error handling settings */ int error_mode = php_stream_get_error_mode(context); int store_mode = php_stream_get_error_store_mode(context, error_mode); bool is_terminating = php_stream_has_terminating_error(op); - /* Always report errors */ php_stream_report_errors(context, op, error_mode, is_terminating); - /* Handle storage */ if (store_mode == PHP_STREAM_ERROR_STORE_NONE) { - /* Free all errors */ php_stream_error_entry_free(op->first_error); op->first_error = NULL; } else { - /* Filter and store */ php_stream_error_entry *entry = op->first_error; php_stream_error_entry *prev = NULL; php_stream_error_entry *to_store_first = NULL; @@ -446,7 +405,6 @@ PHPAPI void php_stream_error_operation_end(php_stream_context *context) } if (should_store) { - /* Move to storage chain */ entry->next = NULL; if (to_store_last) { to_store_last->next = entry; @@ -455,7 +413,6 @@ PHPAPI void php_stream_error_operation_end(php_stream_context *context) } to_store_last = entry; } else { - /* Keep in remaining chain (to be freed) */ entry->next = NULL; if (prev) { prev->next = entry; @@ -468,7 +425,6 @@ PHPAPI void php_stream_error_operation_end(php_stream_context *context) entry = next; } - /* Store filtered errors if any */ if (to_store_first) { php_stream_stored_error *stored = emalloc(sizeof(php_stream_stored_error)); stored->first_error = to_store_first; @@ -478,7 +434,6 @@ PHPAPI void php_stream_error_operation_end(php_stream_context *context) state->stored_count++; } - /* Free remaining errors that were not stored */ if (remaining_first) { php_stream_error_entry_free(remaining_first); } @@ -487,7 +442,6 @@ PHPAPI void php_stream_error_operation_end(php_stream_context *context) } } - /* Reset operation for reuse */ op->first_error = NULL; op->last_error = NULL; op->error_count = 0; @@ -502,18 +456,15 @@ PHPAPI void php_stream_error_operation_end_for_stream(php_stream *stream) return; } - /* Fast path: no errors - just pop and return */ if (op->error_count == 0) { state->operation_depth--; state->current_operation = php_stream_get_parent_operation(); - /* Reset operation for reuse */ op->first_error = NULL; op->last_error = NULL; return; } - /* Slow path: have errors - fetch context and process */ php_stream_context *context = PHP_STREAM_CONTEXT(stream); php_stream_error_operation_end(context); } @@ -527,11 +478,9 @@ PHPAPI void php_stream_error_operation_abort(void) return; } - /* Pop from stack */ state->operation_depth--; state->current_operation = php_stream_get_parent_operation(); - /* Free errors and reset operation */ php_stream_error_entry_free(op->first_error); op->first_error = NULL; op->last_error = NULL; @@ -541,19 +490,16 @@ PHPAPI void php_stream_error_operation_abort(void) /* Wrapper error reporting */ static void php_stream_wrapper_error_internal(const char *wrapper_name, php_stream_context *context, - const char *docref, int options, int severity, bool terminating, int code, char *param, - zend_string *message) + const char *docref, int options, int severity, bool terminating, + zend_enum_StreamErrorCode code, char *param, zend_string *message) { - /* If not in an operation, create one */ bool implicit_operation = (FG(stream_error_state).current_operation == NULL); if (implicit_operation) { php_stream_error_operation_begin(); } - /* Add to current operation (or skip if no operation) */ php_stream_error_add(code, wrapper_name, message, docref, param, severity, terminating); - /* If we created implicit operation, end it immediately */ if (implicit_operation) { php_stream_error_operation_end(context); } @@ -561,7 +507,7 @@ static void php_stream_wrapper_error_internal(const char *wrapper_name, php_stre PHPAPI void php_stream_wrapper_error_with_name(const char *wrapper_name, php_stream_context *context, const char *docref, int options, int severity, - bool terminating, int code, const char *fmt, ...) + bool terminating, zend_enum_StreamErrorCode code, const char *fmt, ...) { if (!(options & REPORT_ERRORS)) { return; @@ -577,8 +523,8 @@ PHPAPI void php_stream_wrapper_error_with_name(const char *wrapper_name, } PHPAPI void php_stream_wrapper_error(php_stream_wrapper *wrapper, php_stream_context *context, - const char *docref, int options, int severity, bool terminating, int code, const char *fmt, - ...) + const char *docref, int options, int severity, bool terminating, + zend_enum_StreamErrorCode code, const char *fmt, ...) { if (!(options & REPORT_ERRORS)) { return; @@ -596,8 +542,8 @@ PHPAPI void php_stream_wrapper_error(php_stream_wrapper *wrapper, php_stream_con } PHPAPI void php_stream_wrapper_error_param(php_stream_wrapper *wrapper, php_stream_context *context, - const char *docref, int options, int severity, bool terminating, int code, - const char *param, const char *fmt, ...) + const char *docref, int options, int severity, bool terminating, + zend_enum_StreamErrorCode code, const char *param, const char *fmt, ...) { if (!(options & REPORT_ERRORS)) { return; @@ -617,7 +563,8 @@ PHPAPI void php_stream_wrapper_error_param(php_stream_wrapper *wrapper, php_stre PHPAPI void php_stream_wrapper_error_param2(php_stream_wrapper *wrapper, php_stream_context *context, const char *docref, int options, int severity, - bool terminating, int code, const char *param1, const char *param2, const char *fmt, ...) + bool terminating, zend_enum_StreamErrorCode code, const char *param1, const char *param2, + const char *fmt, ...) { if (!(options & REPORT_ERRORS)) { return; @@ -637,10 +584,10 @@ PHPAPI void php_stream_wrapper_error_param2(php_stream_wrapper *wrapper, code, combined_param, message); } -/* Stream error reporting - delegates to wrapper errors */ +/* Stream error reporting */ -PHPAPI void php_stream_error(php_stream *stream, const char *docref, int severity, bool terminating, - int code, const char *fmt, ...) +PHPAPI void php_stream_error(php_stream *stream, const char *docref, int severity, + bool terminating, zend_enum_StreamErrorCode code, const char *fmt, ...) { va_list args; va_start(args, fmt); @@ -652,7 +599,6 @@ PHPAPI void php_stream_error(php_stream *stream, const char *docref, int severit php_stream_context *context = PHP_STREAM_CONTEXT(stream); - /* Just call the wrapper error function */ php_stream_wrapper_error_internal(wrapper_name, context, docref, REPORT_ERRORS, severity, terminating, code, NULL, message); } @@ -676,7 +622,7 @@ static void php_stream_error_list_dtor(zval *item) efree(list); } -static void php_stream_wrapper_log_store_error(zend_string *message, int code, +static void php_stream_wrapper_log_store_error(zend_string *message, zend_enum_StreamErrorCode code, const char *wrapper_name, const char *param, int severity, bool terminating) { char *param_copy = param ? estrdup(param) : NULL; @@ -709,26 +655,24 @@ static void php_stream_wrapper_log_store_error(zend_string *message, int code, } static void php_stream_wrapper_log_error_internal(const php_stream_wrapper *wrapper, - php_stream_context *context, int options, int severity, bool terminating, int code, - char *param, const char *fmt, va_list args) + php_stream_context *context, int options, int severity, bool terminating, + zend_enum_StreamErrorCode code, char *param, const char *fmt, va_list args) { zend_string *message = vstrpprintf(0, fmt, args); const char *wrapper_name = PHP_STREAM_ERROR_WRAPPER_NAME(wrapper); if (options & REPORT_ERRORS) { - /* Report immediately */ php_stream_wrapper_error_internal( wrapper_name, context, NULL, options, severity, terminating, code, param, message); } else { - /* Store for later display */ php_stream_wrapper_log_store_error( message, code, wrapper_name, param, severity, terminating); } } PHPAPI void php_stream_wrapper_log_error(const php_stream_wrapper *wrapper, - php_stream_context *context, int options, int severity, bool terminating, int code, - const char *fmt, ...) + php_stream_context *context, int options, int severity, bool terminating, + zend_enum_StreamErrorCode code, const char *fmt, ...) { va_list args; va_start(args, fmt); @@ -738,8 +682,8 @@ PHPAPI void php_stream_wrapper_log_error(const php_stream_wrapper *wrapper, } PHPAPI void php_stream_wrapper_log_error_param(const php_stream_wrapper *wrapper, - php_stream_context *context, int options, int severity, bool terminating, int code, - const char *param, const char *fmt, ...) + php_stream_context *context, int options, int severity, bool terminating, + zend_enum_StreamErrorCode code, const char *param, const char *fmt, ...) { va_list args; va_start(args, fmt); @@ -759,7 +703,8 @@ static zend_llist *php_stream_get_wrapper_errors_list(const char *wrapper_name) } PHPAPI void php_stream_display_wrapper_name_errors(const char *wrapper_name, - php_stream_context *context, int code, const char *path, const char *caption) + php_stream_context *context, zend_enum_StreamErrorCode code, const char *path, + const char *caption) { char *msg; char errstr[256]; @@ -822,8 +767,8 @@ PHPAPI void php_stream_display_wrapper_name_errors(const char *wrapper_name, zend_string *message = strpprintf(0, "%s: %s", caption, msg); - php_stream_wrapper_error_internal( - wrapper_name, context, NULL, REPORT_ERRORS, E_WARNING, true, code, tmp, message); + php_stream_wrapper_error_internal(wrapper_name, context, NULL, REPORT_ERRORS, E_WARNING, true, + code, tmp, message); if (free_msg) { efree(msg); @@ -831,7 +776,8 @@ PHPAPI void php_stream_display_wrapper_name_errors(const char *wrapper_name, } PHPAPI void php_stream_display_wrapper_errors(php_stream_wrapper *wrapper, - php_stream_context *context, int code, const char *path, const char *caption) + php_stream_context *context, zend_enum_StreamErrorCode code, const char *path, + const char *caption) { if (wrapper) { const char *wrapper_name = PHP_STREAM_ERROR_WRAPPER_NAME(wrapper); @@ -854,8 +800,6 @@ PHPAPI void php_stream_tidy_wrapper_error_log(php_stream_wrapper *wrapper) } } -/* StreamError object creation - no enum cache */ - PHPAPI void php_stream_error_create_object(zval *zv, php_stream_error_entry *entry) { if (!entry) { @@ -865,16 +809,10 @@ PHPAPI void php_stream_error_create_object(zval *zv, php_stream_error_entry *ent object_init_ex(zv, php_ce_stream_error); - /* Get enum case by value using lookup array */ const char *case_name = NULL; - int code_value = (int) entry->code; - - if (code_value >= 0 - && code_value < (int) (sizeof(php_stream_error_code_names) - / sizeof(php_stream_error_code_names[0]))) { - case_name = php_stream_error_code_names[code_value]; + if (entry->code > 0 && entry->code <= ZEND_ENUM_StreamErrorCode_CASE_COUNT) { + case_name = zend_enum_StreamErrorCode_case_names[entry->code]; } - if (!case_name) { case_name = "Generic"; } @@ -883,13 +821,11 @@ PHPAPI void php_stream_error_create_object(zval *zv, php_stream_error_entry *ent ZEND_ASSERT(enum_obj != NULL); zval code_enum; - ZVAL_OBJ(&code_enum, enum_obj); - GC_ADDREF(enum_obj); + ZVAL_OBJ_COPY(&code_enum, enum_obj); zend_update_property(php_ce_stream_error, Z_OBJ_P(zv), ZEND_STRL("code"), &code_enum); zval_ptr_dtor(&code_enum); - /* Set other properties */ zend_update_property_str( php_ce_stream_error, Z_OBJ_P(zv), ZEND_STRL("message"), entry->message); @@ -926,7 +862,7 @@ PHP_METHOD(StreamError, hasCode) zval *search_code; ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_OBJECT_OF_CLASS(search_code, php_ce_stream_error_code) + Z_PARAM_OBJECT_OF_CLASS(search_code, php_ce_stream_error_code) ZEND_PARSE_PARAMETERS_END(); zval *current_error_zv = ZEND_THIS; @@ -935,12 +871,10 @@ PHP_METHOD(StreamError, hasCode) zval *code_zv = zend_read_property( php_ce_stream_error, Z_OBJ_P(current_error_zv), ZEND_STRL("code"), 1, NULL); - /* Compare enum objects */ if (Z_TYPE_P(code_zv) == IS_OBJECT && Z_OBJ_P(code_zv) == Z_OBJ_P(search_code)) { RETURN_TRUE; } - /* Move to next error */ current_error_zv = zend_read_property( php_ce_stream_error, Z_OBJ_P(current_error_zv), ZEND_STRL("next"), 1, NULL); @@ -985,121 +919,90 @@ PHP_METHOD(StreamException, getError) RETURN_COPY(error); } -/* StreamErrorCode helper */ +/* StreamErrorCode range helpers - case_id based */ static bool php_stream_error_code_in_range(zval *this_zv, int start, int end) { - zval *backing = zend_enum_fetch_case_value(Z_OBJ_P(this_zv)); - if (!backing || Z_TYPE_P(backing) != IS_LONG) { - return false; - } - - zend_long value = Z_LVAL_P(backing); - return value >= start && value < end; + int case_id = zend_enum_fetch_case_id(Z_OBJ_P(this_zv)); + return case_id >= start && case_id < end; } -/* StreamErrorCode methods */ - PHP_METHOD(StreamErrorCode, isIoError) { ZEND_PARSE_PARAMETERS_NONE(); - - RETURN_BOOL(php_stream_error_code_in_range( - ZEND_THIS, STREAM_ERROR_CODE_IO_START, STREAM_ERROR_CODE_IO_END)); + RETURN_BOOL(php_stream_error_code_in_range(ZEND_THIS, STREAM_EC_IO_START, STREAM_EC_IO_END)); } PHP_METHOD(StreamErrorCode, isFileSystemError) { ZEND_PARSE_PARAMETERS_NONE(); - - RETURN_BOOL(php_stream_error_code_in_range( - ZEND_THIS, STREAM_ERROR_CODE_FILESYSTEM_START, STREAM_ERROR_CODE_FILESYSTEM_END)); + RETURN_BOOL(php_stream_error_code_in_range(ZEND_THIS, STREAM_EC_FS_START, STREAM_EC_FS_END)); } PHP_METHOD(StreamErrorCode, isWrapperError) { ZEND_PARSE_PARAMETERS_NONE(); - RETURN_BOOL(php_stream_error_code_in_range( - ZEND_THIS, STREAM_ERROR_CODE_WRAPPER_START, STREAM_ERROR_CODE_WRAPPER_END)); + ZEND_THIS, STREAM_EC_WRAPPER_START, STREAM_EC_WRAPPER_END)); } PHP_METHOD(StreamErrorCode, isFilterError) { ZEND_PARSE_PARAMETERS_NONE(); - RETURN_BOOL(php_stream_error_code_in_range( - ZEND_THIS, STREAM_ERROR_CODE_FILTER_START, STREAM_ERROR_CODE_FILTER_END)); + ZEND_THIS, STREAM_EC_FILTER_START, STREAM_EC_FILTER_END)); } PHP_METHOD(StreamErrorCode, isCastError) { ZEND_PARSE_PARAMETERS_NONE(); - RETURN_BOOL(php_stream_error_code_in_range( - ZEND_THIS, STREAM_ERROR_CODE_CAST_START, STREAM_ERROR_CODE_CAST_END)); + ZEND_THIS, STREAM_EC_CAST_START, STREAM_EC_CAST_END)); } PHP_METHOD(StreamErrorCode, isNetworkError) { ZEND_PARSE_PARAMETERS_NONE(); - RETURN_BOOL(php_stream_error_code_in_range( - ZEND_THIS, STREAM_ERROR_CODE_NETWORK_START, STREAM_ERROR_CODE_NETWORK_END)); + ZEND_THIS, STREAM_EC_NETWORK_START, STREAM_EC_NETWORK_END)); } PHP_METHOD(StreamErrorCode, isEncodingError) { ZEND_PARSE_PARAMETERS_NONE(); - RETURN_BOOL(php_stream_error_code_in_range( - ZEND_THIS, STREAM_ERROR_CODE_ENCODING_START, STREAM_ERROR_CODE_ENCODING_END)); + ZEND_THIS, STREAM_EC_ENCODING_START, STREAM_EC_ENCODING_END)); } PHP_METHOD(StreamErrorCode, isResourceError) { ZEND_PARSE_PARAMETERS_NONE(); - RETURN_BOOL(php_stream_error_code_in_range( - ZEND_THIS, STREAM_ERROR_CODE_RESOURCE_START, STREAM_ERROR_CODE_RESOURCE_END)); + ZEND_THIS, STREAM_EC_RESOURCE_START, STREAM_EC_RESOURCE_END)); } PHP_METHOD(StreamErrorCode, isLockError) { ZEND_PARSE_PARAMETERS_NONE(); - RETURN_BOOL(php_stream_error_code_in_range( - ZEND_THIS, STREAM_ERROR_CODE_LOCK_START, STREAM_ERROR_CODE_LOCK_END)); + ZEND_THIS, STREAM_EC_LOCK_START, STREAM_EC_LOCK_END)); } PHP_METHOD(StreamErrorCode, isUserspaceError) { ZEND_PARSE_PARAMETERS_NONE(); - RETURN_BOOL(php_stream_error_code_in_range( - ZEND_THIS, STREAM_ERROR_CODE_USERSPACE_START, STREAM_ERROR_CODE_USERSPACE_END)); + ZEND_THIS, STREAM_EC_USERSPACE_START, STREAM_EC_USERSPACE_END)); } /* Module init */ PHP_MINIT_FUNCTION(stream_errors) { - /* Register enums */ php_ce_stream_error_code = register_class_StreamErrorCode(); php_ce_stream_error_mode = register_class_StreamErrorMode(); php_ce_stream_error_store = register_class_StreamErrorStore(); - /* Add cases to StreamErrorCode */ -#define V(uc_name, name, val) \ - { \ - zval enum_case_value; \ - ZVAL_LONG(&enum_case_value, val); \ - zend_enum_add_case_cstr(php_ce_stream_error_code, #name, &enum_case_value); \ - } - PHP_STREAM_ERROR_CODES(V) -#undef V - - /* Register classes */ php_ce_stream_error = register_class_StreamError(); php_ce_stream_exception = register_class_StreamException(zend_ce_exception); diff --git a/main/streams/stream_errors.stub.php b/main/streams/stream_errors.stub.php index 8b6b549a68eb7..3540ff6f461fb 100644 --- a/main/streams/stream_errors.stub.php +++ b/main/streams/stream_errors.stub.php @@ -1,29 +1,129 @@ ops->write == NULL) { - php_stream_notice(stream, STREAM_ERROR_CODE_NOT_WRITABLE, "Stream is not writable"); + php_stream_notice(stream, NotWritable, "Stream is not writable"); return (ssize_t) -1; } @@ -1324,7 +1324,7 @@ PHPAPI int _php_stream_seek(php_stream *stream, zend_off_t offset, int whence) return 0; } - php_stream_warn(stream, STREAM_ERROR_CODE_SEEK_NOT_SUPPORTED, + php_stream_warn(stream, SeekNotSupported, "Stream does not support seeking"); return -1; @@ -1923,7 +1923,7 @@ PHPAPI php_stream_wrapper *php_stream_locate_url_wrapper(const char *path, const #endif if (options & REPORT_ERRORS) { php_stream_wrapper_warn(plain_files_wrapper, NULL, options, - STREAM_ERROR_CODE_PROTOCOL_UNSUPPORTED, + ProtocolUnsupported, "Remote host file access not supported, %s", path); } return NULL; @@ -1964,7 +1964,7 @@ PHPAPI php_stream_wrapper *php_stream_locate_url_wrapper(const char *path, const if (options & REPORT_ERRORS) { php_stream_wrapper_warn(plain_files_wrapper, NULL, options, - STREAM_ERROR_CODE_DISABLED, + Disabled, "file:// wrapper is disabled in the server configuration"); } return NULL; @@ -2064,11 +2064,11 @@ PHPAPI php_stream *_php_stream_opendir(const char *path, int options, } } else if (wrapper) { php_stream_wrapper_log_warn(wrapper, context, options & ~REPORT_ERRORS, - STREAM_ERROR_CODE_NO_OPENER, "not implemented"); + NoOpener, "not implemented"); } if (stream == NULL && (options & REPORT_ERRORS)) { - php_stream_display_wrapper_errors(wrapper, context, STREAM_ERROR_CODE_OPEN_FAILED, path, - "Failed to open directory"); + php_stream_display_wrapper_errors(wrapper, context, PHP_STREAM_EC(OpenFailed), + path, "Failed to open directory"); } php_stream_tidy_wrapper_error_log(wrapper); @@ -2137,7 +2137,7 @@ PHPAPI php_stream *_php_stream_open_wrapper_ex(const char *path, const char *mod if ((options & STREAM_USE_URL) && (!wrapper || !wrapper->is_url)) { if (wrapper) { php_stream_wrapper_warn(wrapper, context, options, - STREAM_ERROR_CODE_PROTOCOL_UNSUPPORTED, + ProtocolUnsupported, "This function may only be used against URLs"); } else { php_error_docref(NULL, E_WARNING, "This function may only be used against URLs"); @@ -2153,7 +2153,7 @@ PHPAPI php_stream *_php_stream_open_wrapper_ex(const char *path, const char *mod if (wrapper) { if (!wrapper->wops->stream_opener) { php_stream_wrapper_log_warn(wrapper, context, options & ~REPORT_ERRORS, - STREAM_ERROR_CODE_NO_OPENER, + NoOpener, "wrapper does not support stream open"); } else { stream = wrapper->wops->stream_opener(wrapper, @@ -2165,7 +2165,7 @@ PHPAPI php_stream *_php_stream_open_wrapper_ex(const char *path, const char *mod * return one, force an error here */ if (stream && persistent && !stream->is_persistent) { php_stream_wrapper_log_warn(wrapper, context, options & ~REPORT_ERRORS, - STREAM_ERROR_CODE_PERSISTENT_NOT_SUPPORTED, + PersistentNotSupported, "wrapper does not support persistent streams"); php_stream_close(stream); stream = NULL; @@ -2223,7 +2223,7 @@ PHPAPI php_stream *_php_stream_open_wrapper_ex(const char *path, const char *mod char *tmp = estrdup(path); php_strip_url_passwd(tmp); php_stream_wrapper_warn_param(wrapper, context, options, - STREAM_ERROR_CODE_SEEK_NOT_SUPPORTED, tmp, + SeekNotSupported, tmp, "could not make seekable - %s", tmp); efree(tmp); @@ -2242,8 +2242,8 @@ PHPAPI php_stream *_php_stream_open_wrapper_ex(const char *path, const char *mod } if (stream == NULL && (options & REPORT_ERRORS)) { - php_stream_display_wrapper_name_errors(wrapper_name, context, STREAM_ERROR_CODE_OPEN_FAILED, path, - "Failed to open stream"); + php_stream_display_wrapper_name_errors(wrapper_name, context, PHP_STREAM_EC(OpenFailed), + path, "Failed to open stream"); if (opened_path && *opened_path) { zend_string_release_ex(*opened_path, 0); *opened_path = NULL; diff --git a/main/streams/transports.c b/main/streams/transports.c index ceab9a083de82..64f52e31d13de 100644 --- a/main/streams/transports.c +++ b/main/streams/transports.c @@ -116,7 +116,7 @@ PHPAPI php_stream *_php_stream_xport_create(const char *name, size_t namelen, in n = sizeof(wrapper_name) - 1; PHP_STRLCPY(wrapper_name, protocol, sizeof(wrapper_name), n); - ERR_REPORT(STREAM_ERROR_CODE_WRAPPER_NOT_FOUND, error_string, + ERR_REPORT(WrapperNotFound, error_string, "Unable to find the socket transport \"%s\" - did you forget to enable it when you configured PHP?", wrapper_name); @@ -127,7 +127,7 @@ PHPAPI php_stream *_php_stream_xport_create(const char *name, size_t namelen, in if (factory == NULL) { /* should never happen */ php_stream_wrapper_warn(NULL, context, REPORT_ERRORS, - STREAM_ERROR_CODE_WRAPPER_NOT_FOUND, "Could not find a factory !?"); + WrapperNotFound, "Could not find a factory !?"); return NULL; } @@ -148,7 +148,7 @@ PHPAPI php_stream *_php_stream_xport_create(const char *name, size_t namelen, in flags & STREAM_XPORT_CONNECT_ASYNC ? 1 : 0, timeout, &error_text, error_code)) { - ERR_RETURN(STREAM_ERROR_CODE_CONNECT_FAILED, error_string, error_text, "connect() failed: %s"); + ERR_RETURN(ConnectFailed, error_string, error_text, "connect() failed: %s"); failed = true; } @@ -158,7 +158,7 @@ PHPAPI php_stream *_php_stream_xport_create(const char *name, size_t namelen, in /* server */ if (flags & STREAM_XPORT_BIND) { if (0 != php_stream_xport_bind(stream, name, namelen, &error_text)) { - ERR_RETURN(STREAM_ERROR_CODE_BIND_FAILED, error_string, error_text, "bind() failed: %s"); + ERR_RETURN(BindFailed, error_string, error_text, "bind() failed: %s"); failed = true; } else if (flags & STREAM_XPORT_LISTEN) { zval *zbacklog = NULL; @@ -169,7 +169,7 @@ PHPAPI php_stream *_php_stream_xport_create(const char *name, size_t namelen, in } if (0 != php_stream_xport_listen(stream, backlog, &error_text)) { - ERR_RETURN(STREAM_ERROR_CODE_LISTEN_FAILED, error_string, error_text, "listen() failed: %s"); + ERR_RETURN(ListenFailed, error_string, error_text, "listen() failed: %s"); failed = true; } } @@ -372,7 +372,7 @@ PHPAPI int php_stream_xport_crypto_setup(php_stream *stream, php_stream_xport_cr return param.outputs.returncode; } - php_stream_warn_docref(stream, "streams.crypto", STREAM_ERROR_CODE_SSL_NOT_SUPPORTED, + php_stream_warn_docref(stream, "streams.crypto", SslNotSupported, "This stream does not support SSL/crypto"); return ret; @@ -393,7 +393,7 @@ PHPAPI int php_stream_xport_crypto_enable(php_stream *stream, int activate) return param.outputs.returncode; } - php_stream_warn_docref(stream, "streams.crypto", STREAM_ERROR_CODE_SSL_NOT_SUPPORTED, + php_stream_warn_docref(stream, "streams.crypto", SslNotSupported, "This stream does not support SSL/crypto"); return ret; @@ -416,7 +416,7 @@ PHPAPI int php_stream_xport_recvfrom(php_stream *stream, char *buf, size_t bufle } if (stream->readfilters.head) { - php_stream_warn(stream, STREAM_ERROR_CODE_FILTER_FAILED, + php_stream_warn(stream, FilterFailed, "Cannot peek or fetch OOB data from a filtered stream"); return -1; } @@ -487,7 +487,7 @@ PHPAPI int php_stream_xport_sendto(php_stream *stream, const char *buf, size_t b oob = (flags & STREAM_OOB) == STREAM_OOB; if ((oob || addr) && stream->writefilters.head) { - php_stream_warn(stream, STREAM_ERROR_CODE_FILTER_FAILED, + php_stream_warn(stream, FilterFailed, "Cannot write OOB data, or data to a targeted address on a filtered stream"); return -1; } diff --git a/main/streams/userspace.c b/main/streams/userspace.c index 4ba3bed83d3be..ec116a0839bb0 100644 --- a/main/streams/userspace.c +++ b/main/streams/userspace.c @@ -294,7 +294,7 @@ static php_stream *user_wrapper_opener(php_stream_wrapper *wrapper, const char * /* Try to catch bad usage without preventing flexibility */ if (FG(user_stream_current_filename) != NULL && strcmp(filename, FG(user_stream_current_filename)) == 0) { php_stream_wrapper_log_warn(wrapper, context, options, - STREAM_ERROR_CODE_RECURSION_DETECTED, "infinite recursion prevented"); + RecursionDetected, "infinite recursion prevented"); return NULL; } FG(user_stream_current_filename) = filename; @@ -335,7 +335,7 @@ static php_stream *user_wrapper_opener(php_stream_wrapper *wrapper, const char * zval_ptr_dtor(&args[0]); if (UNEXPECTED(call_result == FAILURE)) { - php_stream_wrapper_log_warn(wrapper, context, options,STREAM_ERROR_CODE_NOT_IMPLEMENTED, + php_stream_wrapper_log_warn(wrapper, context, options,NotImplemented, "\"%s::" USERSTREAM_OPEN "\" is not implemented", ZSTR_VAL(us->wrapper->ce->name)); zval_ptr_dtor(&args[3]); goto end; @@ -359,7 +359,7 @@ static php_stream *user_wrapper_opener(php_stream_wrapper *wrapper, const char * ZVAL_COPY(&stream->wrapperdata, &us->object); } else { php_stream_wrapper_log_warn(wrapper, context, options, - STREAM_ERROR_CODE_USERSPACE_CALL_FAILED, + UserspaceCallFailed, "\"%s::" USERSTREAM_OPEN "\" call failed", ZSTR_VAL(us->wrapper->ce->name)); } @@ -397,7 +397,7 @@ static php_stream *user_wrapper_opendir(php_stream_wrapper *wrapper, const char /* Try to catch bad usage without preventing flexibility */ if (FG(user_stream_current_filename) != NULL && strcmp(filename, FG(user_stream_current_filename)) == 0) { php_stream_wrapper_log_warn(wrapper, context, options, - STREAM_ERROR_CODE_RECURSION_DETECTED, "infinite recursion prevented"); + RecursionDetected, "infinite recursion prevented"); return NULL; } FG(user_stream_current_filename) = filename; @@ -422,7 +422,7 @@ static php_stream *user_wrapper_opendir(php_stream_wrapper *wrapper, const char zval_ptr_dtor(&args[0]); if (UNEXPECTED(call_result == FAILURE)) { - php_stream_wrapper_log_warn(wrapper, context, options, STREAM_ERROR_CODE_NOT_IMPLEMENTED, + php_stream_wrapper_log_warn(wrapper, context, options, NotImplemented, "\"%s::" USERSTREAM_DIR_OPEN "\" is not implemented", ZSTR_VAL(us->wrapper->ce->name)); goto end; @@ -440,7 +440,7 @@ static php_stream *user_wrapper_opendir(php_stream_wrapper *wrapper, const char ZVAL_COPY(&stream->wrapperdata, &us->object); } else { php_stream_wrapper_log_warn(wrapper, context, options, - STREAM_ERROR_CODE_USERSPACE_CALL_FAILED, + UserspaceCallFailed, "\"%s::" USERSTREAM_DIR_OPEN "\" call failed", ZSTR_VAL(us->wrapper->ce->name)); } zval_ptr_dtor(&zretval); @@ -485,12 +485,12 @@ PHP_FUNCTION(stream_wrapper_register) /* We failed. But why? */ if (zend_hash_exists(php_stream_get_url_stream_wrappers_hash(), protocol)) { php_stream_wrapper_warn(&uwrap->wrapper, NULL, REPORT_ERRORS, - STREAM_ERROR_CODE_WRAPPER_REGISTRATION_FAILED, + WrapperRegistrationFailed, "Protocol %s:// is already defined.", ZSTR_VAL(protocol)); } else { /* Hash doesn't exist so it must have been an invalid protocol scheme */ php_stream_wrapper_warn(&uwrap->wrapper, NULL, REPORT_ERRORS, - STREAM_ERROR_CODE_WRAPPER_REGISTRATION_FAILED, + WrapperRegistrationFailed, "Invalid protocol scheme specified. Unable to register wrapper class %s to %s://", ZSTR_VAL(uwrap->ce->name), ZSTR_VAL(protocol)); } @@ -513,7 +513,7 @@ PHP_FUNCTION(stream_wrapper_unregister) if (php_unregister_url_stream_wrapper_volatile(protocol) == FAILURE) { /* We failed */ php_stream_wrapper_warn(wrapper, NULL, REPORT_ERRORS, - STREAM_ERROR_CODE_WRAPPER_UNREGISTRATION_FAILED, + WrapperUnregistrationFailed, "Unable to unregister protocol %s://", ZSTR_VAL(protocol)); RETURN_FALSE; } @@ -543,7 +543,7 @@ PHP_FUNCTION(stream_wrapper_restore) global_wrapper_hash = php_stream_get_url_stream_wrappers_hash_global(); if ((wrapper = zend_hash_find_ptr(global_wrapper_hash, protocol)) == NULL) { php_stream_wrapper_warn_name(user_stream_wops.label, NULL, REPORT_ERRORS, - STREAM_ERROR_CODE_WRAPPER_NOT_FOUND, + WrapperNotFound, "%s:// never existed, nothing to restore", ZSTR_VAL(protocol)); RETURN_FALSE; } @@ -551,7 +551,7 @@ PHP_FUNCTION(stream_wrapper_restore) wrapper_hash = php_stream_get_url_stream_wrappers_hash(); if (wrapper_hash == global_wrapper_hash || zend_hash_find_ptr(wrapper_hash, protocol) == wrapper) { php_stream_wrapper_notice(wrapper, NULL, REPORT_ERRORS, - STREAM_ERROR_CODE_WRAPPER_RESTORATION_FAILED, + WrapperRestorationFailed, "%s:// was never changed, nothing to restore", ZSTR_VAL(protocol)); RETURN_TRUE; } @@ -561,7 +561,7 @@ PHP_FUNCTION(stream_wrapper_restore) if (php_register_url_stream_wrapper_volatile(protocol, wrapper) == FAILURE) { php_stream_wrapper_warn(wrapper, NULL, REPORT_ERRORS, - STREAM_ERROR_CODE_WRAPPER_RESTORATION_FAILED, + WrapperRestorationFailed, "Unable to restore original %s:// wrapper", ZSTR_VAL(protocol)); RETURN_FALSE; } @@ -590,7 +590,7 @@ static ssize_t php_userstreamop_write(php_stream *stream, const char *buf, size_ zval_ptr_dtor(&args[0]); if (UNEXPECTED(call_result == FAILURE)) { - php_stream_warn(stream, STREAM_ERROR_CODE_NOT_IMPLEMENTED, + php_stream_warn(stream, NotImplemented, "%s::" USERSTREAM_WRITE " is not implemented!", ZSTR_VAL(us->wrapper->ce->name)); } @@ -611,7 +611,7 @@ static ssize_t php_userstreamop_write(php_stream *stream, const char *buf, size_ /* don't allow strange buffer overruns due to bogus return */ if (didwrite > 0 && didwrite > count) { - php_stream_warn_nt(stream, STREAM_ERROR_CODE_USERSPACE_INVALID_RETURN, + php_stream_warn_nt(stream, UserspaceInvalidReturn, "%s::" USERSTREAM_WRITE " wrote " ZEND_LONG_FMT " bytes more data than requested (" ZEND_LONG_FMT " written, " ZEND_LONG_FMT " max)", ZSTR_VAL(us->wrapper->ce->name), @@ -644,7 +644,7 @@ static ssize_t php_userstreamop_read(php_stream *stream, char *buf, size_t count } if (UNEXPECTED(call_result == FAILURE)) { - php_stream_warn(stream, STREAM_ERROR_CODE_NOT_IMPLEMENTED, + php_stream_warn(stream, NotImplemented, "%s::" USERSTREAM_READ " is not implemented!", ZSTR_VAL(us->wrapper->ce->name)); goto err; } @@ -661,7 +661,7 @@ static ssize_t php_userstreamop_read(php_stream *stream, char *buf, size_t count didread = Z_STRLEN(retval); if (didread > 0) { if (didread > count) { - php_stream_warn_nt(stream, STREAM_ERROR_CODE_USERSPACE_INVALID_RETURN, + php_stream_warn_nt(stream, UserspaceInvalidReturn, "%s::" USERSTREAM_READ " - read " ZEND_LONG_FMT " bytes more data than requested (" ZEND_LONG_FMT " read, " ZEND_LONG_FMT " max) - excess data will be lost", @@ -682,7 +682,7 @@ static ssize_t php_userstreamop_read(php_stream *stream, char *buf, size_t count zend_string_release_ex(func_name, false); if (UNEXPECTED(call_result == FAILURE)) { - php_stream_warn(stream, STREAM_ERROR_CODE_NOT_IMPLEMENTED, + php_stream_warn(stream, NotImplemented, "%s::" USERSTREAM_EOF " is not implemented! Assuming EOF", ZSTR_VAL(us->wrapper->ce->name)); stream->eof = 1; @@ -798,7 +798,7 @@ static int php_userstreamop_seek(php_stream *stream, zend_off_t offset, int when *newoffs = Z_LVAL(retval); ret = 0; } else if (UNEXPECTED(call_result == FAILURE)) { - php_stream_warn(stream, STREAM_ERROR_CODE_NOT_IMPLEMENTED, + php_stream_warn(stream, NotImplemented, "%s::" USERSTREAM_TELL " is not implemented!", ZSTR_VAL(us->wrapper->ce->name)); ret = -1; } else { @@ -863,7 +863,7 @@ static int php_userstreamop_stat(php_stream *stream, php_stream_statbuf *ssb) zend_string_release_ex(func_name, false); if (UNEXPECTED(call_result == FAILURE)) { - php_stream_warn(stream, STREAM_ERROR_CODE_NOT_IMPLEMENTED, + php_stream_warn(stream, NotImplemented, "%s::" USERSTREAM_STAT " is not implemented!", ZSTR_VAL(us->wrapper->ce->name)); return -1; } @@ -891,7 +891,7 @@ static int user_stream_set_check_liveliness(php_stream *stream, const php_userst zend_string_release_ex(func_name, false); if (UNEXPECTED(call_result == FAILURE)) { - php_stream_warn(stream, STREAM_ERROR_CODE_NOT_IMPLEMENTED, + php_stream_warn(stream, NotImplemented, "%s::" USERSTREAM_EOF " is not implemented! Assuming EOF", ZSTR_VAL(us->wrapper->ce->name)); return PHP_STREAM_OPTION_RETURN_ERR; @@ -902,7 +902,7 @@ static int user_stream_set_check_liveliness(php_stream *stream, const php_userst if (EXPECTED(Z_TYPE(retval) == IS_FALSE || Z_TYPE(retval) == IS_TRUE)) { return Z_TYPE(retval) == IS_TRUE ? PHP_STREAM_OPTION_RETURN_ERR : PHP_STREAM_OPTION_RETURN_OK; } else { - php_stream_warn(stream, STREAM_ERROR_CODE_USERSPACE_INVALID_RETURN, + php_stream_warn(stream, UserspaceInvalidReturn, "%s::" USERSTREAM_EOF " value must be of type bool, %s given", ZSTR_VAL(us->wrapper->ce->name), zend_zval_value_name(&retval)); zval_ptr_dtor(&retval); @@ -945,7 +945,7 @@ static int user_stream_set_locking(php_stream *stream, const php_userstream_data /* lock support test (TODO: more check) */ return PHP_STREAM_OPTION_RETURN_OK; } - php_stream_warn(stream, STREAM_ERROR_CODE_NOT_IMPLEMENTED, + php_stream_warn(stream, NotImplemented, "%s::" USERSTREAM_LOCK " is not implemented!", ZSTR_VAL(us->wrapper->ce->name)); return PHP_STREAM_OPTION_RETURN_ERR; } @@ -958,7 +958,7 @@ static int user_stream_set_locking(php_stream *stream, const php_userstream_data } // TODO: ext/standard/tests/file/userstreams_004.phpt returns null implicitly for function // Should this warn or not? And should this be considered an error? - //php_stream_warn(stream, STREAM_ERROR_CODE_USERSPACE_INVALID_RETURN, + //php_stream_warn(stream, UserspaceInvalidReturn, // "%s::" USERSTREAM_LOCK " value must be of type bool, %s given", // ZSTR_VAL(us->wrapper->ce->name), zend_zval_value_name(&retval)); zval_ptr_dtor(&retval); @@ -994,7 +994,7 @@ static int user_stream_set_truncation(php_stream *stream, const php_userstream_d zend_string_release_ex(func_name, false); if (UNEXPECTED(call_result == FAILURE)) { - php_stream_warn(stream, STREAM_ERROR_CODE_NOT_IMPLEMENTED, + php_stream_warn(stream, NotImplemented, "%s::" USERSTREAM_TRUNCATE " is not implemented!", ZSTR_VAL(us->wrapper->ce->name)); return PHP_STREAM_OPTION_RETURN_ERR; } @@ -1004,7 +1004,7 @@ static int user_stream_set_truncation(php_stream *stream, const php_userstream_d if (EXPECTED(Z_TYPE(retval) == IS_FALSE || Z_TYPE(retval) == IS_TRUE)) { return Z_TYPE(retval) == IS_TRUE ? PHP_STREAM_OPTION_RETURN_OK : PHP_STREAM_OPTION_RETURN_ERR; } else { - php_stream_warn(stream, STREAM_ERROR_CODE_USERSPACE_INVALID_RETURN, + php_stream_warn(stream, UserspaceInvalidReturn, "%s::" USERSTREAM_TRUNCATE " value must be of type bool, %s given", ZSTR_VAL(us->wrapper->ce->name), zend_zval_value_name(&retval)); zval_ptr_dtor(&retval); @@ -1038,7 +1038,7 @@ static int user_stream_set_option(php_stream *stream, const php_userstream_data_ zend_string_release_ex(func_name, false); if (UNEXPECTED(call_result == FAILURE)) { - php_stream_warn(stream, STREAM_ERROR_CODE_NOT_IMPLEMENTED, + php_stream_warn(stream, NotImplemented, "%s::" USERSTREAM_SET_OPTION " is not implemented!", ZSTR_VAL(us->wrapper->ce->name)); return PHP_STREAM_OPTION_RETURN_ERR; @@ -1108,7 +1108,7 @@ static int user_wrapper_unlink(php_stream_wrapper *wrapper, const char *url, int zval_ptr_dtor(&object); if (UNEXPECTED(call_result == FAILURE)) { - php_stream_wrapper_warn(wrapper, context, REPORT_ERRORS, STREAM_ERROR_CODE_NOT_IMPLEMENTED, + php_stream_wrapper_warn(wrapper, context, REPORT_ERRORS, NotImplemented, "%s::" USERSTREAM_UNLINK " is not implemented!", ZSTR_VAL(uwrap->ce->name)); } else if (Z_TYPE(zretval) == IS_FALSE || Z_TYPE(zretval) == IS_TRUE) { ret = Z_TYPE(zretval) == IS_TRUE; @@ -1147,7 +1147,7 @@ static int user_wrapper_rename(php_stream_wrapper *wrapper, const char *url_from zval_ptr_dtor(&object); if (UNEXPECTED(call_result == FAILURE)) { - php_stream_wrapper_warn(wrapper, context, REPORT_ERRORS, STREAM_ERROR_CODE_NOT_IMPLEMENTED, + php_stream_wrapper_warn(wrapper, context, REPORT_ERRORS, NotImplemented, "%s::" USERSTREAM_RENAME " is not implemented!", ZSTR_VAL(uwrap->ce->name)); } else if (Z_TYPE(zretval) == IS_FALSE || Z_TYPE(zretval) == IS_TRUE) { ret = Z_TYPE(zretval) == IS_TRUE; @@ -1186,7 +1186,7 @@ static int user_wrapper_mkdir(php_stream_wrapper *wrapper, const char *url, int zval_ptr_dtor(&object); if (UNEXPECTED(call_result == FAILURE)) { - php_stream_wrapper_warn(wrapper, context, REPORT_ERRORS, STREAM_ERROR_CODE_NOT_IMPLEMENTED, + php_stream_wrapper_warn(wrapper, context, REPORT_ERRORS, NotImplemented, "%s::" USERSTREAM_MKDIR " is not implemented!", ZSTR_VAL(uwrap->ce->name)); } else if (Z_TYPE(zretval) == IS_FALSE || Z_TYPE(zretval) == IS_TRUE) { ret = Z_TYPE(zretval) == IS_TRUE; @@ -1224,7 +1224,7 @@ static int user_wrapper_rmdir(php_stream_wrapper *wrapper, const char *url, zval_ptr_dtor(&object); if (UNEXPECTED(call_result == FAILURE)) { - php_stream_wrapper_warn(wrapper, context, REPORT_ERRORS, STREAM_ERROR_CODE_NOT_IMPLEMENTED, + php_stream_wrapper_warn(wrapper, context, REPORT_ERRORS, NotImplemented, "%s::" USERSTREAM_RMDIR " is not implemented!", ZSTR_VAL(uwrap->ce->name)); } else if (Z_TYPE(zretval) == IS_FALSE || Z_TYPE(zretval) == IS_TRUE) { ret = Z_TYPE(zretval) == IS_TRUE; @@ -1265,7 +1265,7 @@ static int user_wrapper_metadata(php_stream_wrapper *wrapper, const char *url, i break; default: php_stream_wrapper_warn(wrapper, context, REPORT_ERRORS, - STREAM_ERROR_CODE_INVALID_META, + InvalidMeta, "Unknown option %d for " USERSTREAM_METADATA, option); return ret; } @@ -1289,7 +1289,7 @@ static int user_wrapper_metadata(php_stream_wrapper *wrapper, const char *url, i zval_ptr_dtor(&object); if (UNEXPECTED(call_result == FAILURE)) { - php_stream_wrapper_warn(wrapper, context, REPORT_ERRORS, STREAM_ERROR_CODE_NOT_IMPLEMENTED, + php_stream_wrapper_warn(wrapper, context, REPORT_ERRORS, NotImplemented, "%s::" USERSTREAM_METADATA " is not implemented!", ZSTR_VAL(uwrap->ce->name)); } else if (Z_TYPE(zretval) == IS_FALSE || Z_TYPE(zretval) == IS_TRUE) { ret = Z_TYPE(zretval) == IS_TRUE; @@ -1328,7 +1328,7 @@ static int user_wrapper_stat_url(php_stream_wrapper *wrapper, const char *url, i zval_ptr_dtor(&object); if (UNEXPECTED(call_result == FAILURE)) { - php_stream_wrapper_warn(wrapper, context, REPORT_ERRORS, STREAM_ERROR_CODE_NOT_IMPLEMENTED, + php_stream_wrapper_warn(wrapper, context, REPORT_ERRORS, NotImplemented, "%s::" USERSTREAM_STATURL " is not implemented!", ZSTR_VAL(uwrap->ce->name)); return -1; } @@ -1364,7 +1364,7 @@ static ssize_t php_userstreamop_readdir(php_stream *stream, char *buf, size_t co zend_string_release_ex(func_name, false); if (UNEXPECTED(call_result == FAILURE)) { - php_stream_warn(stream, STREAM_ERROR_CODE_NOT_IMPLEMENTED, + php_stream_warn(stream, NotImplemented, "%s::" USERSTREAM_DIR_READ " is not implemented!", ZSTR_VAL(us->wrapper->ce->name)); return -1; @@ -1451,7 +1451,7 @@ static int php_userstreamop_cast(php_stream *stream, int castas, void **retptr) if (UNEXPECTED(call_result == FAILURE)) { if (report_errors) { - php_stream_warn(stream, STREAM_ERROR_CODE_NOT_IMPLEMENTED, + php_stream_warn(stream, NotImplemented, "%s::" USERSTREAM_CAST " is not implemented!", ZSTR_VAL(us->wrapper->ce->name)); } @@ -1466,7 +1466,7 @@ static int php_userstreamop_cast(php_stream *stream, int castas, void **retptr) php_stream_from_zval_no_verify(intstream, &retval); if (!intstream) { if (report_errors) { - php_stream_warn(stream, STREAM_ERROR_CODE_USERSPACE_INVALID_RETURN, + php_stream_warn(stream, UserspaceInvalidReturn, "%s::" USERSTREAM_CAST " must return a stream resource", ZSTR_VAL(us->wrapper->ce->name)); } @@ -1474,7 +1474,7 @@ static int php_userstreamop_cast(php_stream *stream, int castas, void **retptr) } if (intstream == stream) { if (report_errors) { - php_stream_warn(stream, STREAM_ERROR_CODE_USERSPACE_INVALID_RETURN, + php_stream_warn(stream, UserspaceInvalidReturn, "%s::" USERSTREAM_CAST " must not return itself", ZSTR_VAL(us->wrapper->ce->name)); } diff --git a/main/streams/xp_socket.c b/main/streams/xp_socket.c index 16e400e1b4f7b..540fb9ad3a65a 100644 --- a/main/streams/xp_socket.c +++ b/main/streams/xp_socket.c @@ -116,7 +116,7 @@ static ssize_t php_sockop_write(php_stream *stream, const char *buf, size_t coun if (!(stream->flags & PHP_STREAM_FLAG_SUPPRESS_ERRORS)) { estr = php_socket_strerror(err, NULL, 0); - php_stream_warn(stream, STREAM_ERROR_CODE_NETWORK_SEND_FAILED, + php_stream_warn(stream, NetworkSendFailed, "Send of %zu bytes failed with errno=%d %s", count, err, estr); efree(estr); } @@ -453,7 +453,7 @@ static int php_sockop_set_option(php_stream *stream, int option, int value, void xparam->inputs.addrlen); if (xparam->outputs.returncode == -1) { char *err = php_socket_strerror(php_socket_errno(), NULL, 0); - php_stream_warn(stream, STREAM_ERROR_CODE_NETWORK_SEND_FAILED, "%s", err); + php_stream_warn(stream, NetworkSendFailed, "%s", err); efree(err); } return PHP_STREAM_OPTION_RETURN_OK; @@ -613,7 +613,7 @@ static inline int parse_unix_address(php_stream *stream, php_stream_xport_param * BUT, to get into this branch of code, the name is too long, * so we don't care. */ xparam->inputs.namelen = max_length; - php_stream_notice(stream, STREAM_ERROR_CODE_INVALID_PATH, + php_stream_notice(stream, InvalidPath, "socket path exceeded the maximum allowed length of %lu bytes and was truncated", max_length); } From 78226808d7135d575a1725455aea86b88a465b10 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Sun, 29 Mar 2026 19:41:57 +0200 Subject: [PATCH 66/68] stream: return array of errors instead of linked list --- ext/standard/basic_functions.stub.php | 5 +- ext/standard/basic_functions_arginfo.h | 13 +- ext/standard/basic_functions_decl.h | 8 +- ext/standard/streamsfuncs.c | 27 +-- .../stream_errors_error_code_helpers.phpt | 5 +- .../streams/stream_errors_error_has_code.phpt | 4 +- ...stream_errors_exception_mode_terminal.phpt | 5 +- .../stream_errors_mix_modes_storage.phpt | 35 +-- .../stream_errors_modes_with_auto_store.phpt | 12 +- .../streams/stream_errors_multi_store.phpt | 23 -- .../stream_errors_silent_with_handler.phpt | 14 +- .../stream_errors_silent_with_storage.phpt | 4 +- .../stream_errors_silent_without_storage.phpt | 4 +- main/streams/php_stream_errors.h | 10 +- main/streams/stream_errors.c | 229 ++++++++---------- main/streams/stream_errors.stub.php | 11 +- main/streams/stream_errors_arginfo.h | 43 +--- main/streams/stream_errors_decl.h | 8 +- 18 files changed, 195 insertions(+), 265 deletions(-) delete mode 100644 ext/standard/tests/streams/stream_errors_multi_store.phpt diff --git a/ext/standard/basic_functions.stub.php b/ext/standard/basic_functions.stub.php index 6ea9915bab0b3..1a5146637a77e 100644 --- a/ext/standard/basic_functions.stub.php +++ b/ext/standard/basic_functions.stub.php @@ -3556,8 +3556,11 @@ function stream_get_wrappers(): array {} /** * @refcount 1 + * @return list */ -function stream_get_last_error(): ?StreamError {} +function stream_last_errors(): array {} + +function stream_clear_errors(): void {} /** * @return array diff --git a/ext/standard/basic_functions_arginfo.h b/ext/standard/basic_functions_arginfo.h index 9a1a6369c9966..29046f7bf5629 100644 --- a/ext/standard/basic_functions_arginfo.h +++ b/ext/standard/basic_functions_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit basic_functions.stub.php instead. - * Stub hash: 6afe0eea6b3b3190ae083bf03e99f2341147684e + * Stub hash: b824f606ebb1daf1ad8df828bfdbf0c9ae985630 * Has decl header: yes */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_set_time_limit, 0, 1, _IS_BOOL, 0) @@ -1990,8 +1990,9 @@ ZEND_END_ARG_INFO() #define arginfo_stream_get_wrappers arginfo_ob_list_handlers -ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_stream_get_last_error, 0, 0, StreamError, 1) -ZEND_END_ARG_INFO() +#define arginfo_stream_last_errors arginfo_ob_list_handlers + +#define arginfo_stream_clear_errors arginfo_flush #define arginfo_stream_get_transports arginfo_ob_list_handlers @@ -2838,7 +2839,8 @@ ZEND_FUNCTION(stream_get_meta_data); ZEND_FUNCTION(stream_get_line); ZEND_FUNCTION(stream_resolve_include_path); ZEND_FUNCTION(stream_get_wrappers); -ZEND_FUNCTION(stream_get_last_error); +ZEND_FUNCTION(stream_last_errors); +ZEND_FUNCTION(stream_clear_errors); ZEND_FUNCTION(stream_get_transports); ZEND_FUNCTION(stream_is_local); ZEND_FUNCTION(stream_isatty); @@ -3447,7 +3449,8 @@ static const zend_function_entry ext_functions[] = { ZEND_FE(stream_get_line, arginfo_stream_get_line) ZEND_FE(stream_resolve_include_path, arginfo_stream_resolve_include_path) ZEND_FE(stream_get_wrappers, arginfo_stream_get_wrappers) - ZEND_FE(stream_get_last_error, arginfo_stream_get_last_error) + ZEND_FE(stream_last_errors, arginfo_stream_last_errors) + ZEND_FE(stream_clear_errors, arginfo_stream_clear_errors) ZEND_FE(stream_get_transports, arginfo_stream_get_transports) ZEND_FE(stream_is_local, arginfo_stream_is_local) ZEND_FE(stream_isatty, arginfo_stream_isatty) diff --git a/ext/standard/basic_functions_decl.h b/ext/standard/basic_functions_decl.h index 7a036c2dca349..640dfeb20d0ac 100644 --- a/ext/standard/basic_functions_decl.h +++ b/ext/standard/basic_functions_decl.h @@ -1,8 +1,8 @@ /* This is a generated file, edit basic_functions.stub.php instead. - * Stub hash: 6afe0eea6b3b3190ae083bf03e99f2341147684e */ + * Stub hash: b824f606ebb1daf1ad8df828bfdbf0c9ae985630 */ -#ifndef ZEND_BASIC_FUNCTIONS_DECL_6afe0eea6b3b3190ae083bf03e99f2341147684e_H -#define ZEND_BASIC_FUNCTIONS_DECL_6afe0eea6b3b3190ae083bf03e99f2341147684e_H +#ifndef ZEND_BASIC_FUNCTIONS_DECL_b824f606ebb1daf1ad8df828bfdbf0c9ae985630_H +#define ZEND_BASIC_FUNCTIONS_DECL_b824f606ebb1daf1ad8df828bfdbf0c9ae985630_H typedef enum zend_enum_RoundingMode { ZEND_ENUM_RoundingMode_HalfAwayFromZero = 1, @@ -15,4 +15,4 @@ typedef enum zend_enum_RoundingMode { ZEND_ENUM_RoundingMode_PositiveInfinity = 8, } zend_enum_RoundingMode; -#endif /* ZEND_BASIC_FUNCTIONS_DECL_6afe0eea6b3b3190ae083bf03e99f2341147684e_H */ +#endif /* ZEND_BASIC_FUNCTIONS_DECL_b824f606ebb1daf1ad8df828bfdbf0c9ae985630_H */ diff --git a/ext/standard/streamsfuncs.c b/ext/standard/streamsfuncs.c index e853e1938aebe..5305d79ffcb8f 100644 --- a/ext/standard/streamsfuncs.c +++ b/ext/standard/streamsfuncs.c @@ -634,25 +634,16 @@ PHP_FUNCTION(stream_get_wrappers) } /* }}} */ -/* Retrieves the last stored stream error */ -PHP_FUNCTION(stream_get_last_error) +PHP_FUNCTION(stream_last_errors) { - ZEND_PARSE_PARAMETERS_NONE(); - - /* Check if we have any stored errors */ - if (!FG(stream_error_state).stored_errors) { - RETURN_NULL(); - } - - /* Get the most recent stored error (head of list) */ - php_stream_stored_error *stored = FG(stream_error_state).stored_errors; - - if (!stored->first_error) { - RETURN_NULL(); - } - - /* Create StreamError object from the error chain */ - php_stream_error_create_object(return_value, stored->first_error); + ZEND_PARSE_PARAMETERS_NONE(); + php_stream_error_get_last(return_value); +} + +PHP_FUNCTION(stream_clear_errors) +{ + ZEND_PARSE_PARAMETERS_NONE(); + php_stream_error_clear_stored(); } /* {{{ stream_select related functions */ diff --git a/ext/standard/tests/streams/stream_errors_error_code_helpers.phpt b/ext/standard/tests/streams/stream_errors_error_code_helpers.phpt index dc452e846fb4b..ae71af2f79d51 100644 --- a/ext/standard/tests/streams/stream_errors_error_code_helpers.phpt +++ b/ext/standard/tests/streams/stream_errors_error_code_helpers.phpt @@ -12,8 +12,9 @@ $context = stream_context_create([ // Generate a network error $stream = fopen('php://nonexistent', 'r', false, $context); -$error = stream_get_last_error(); -if ($error) { +$errors = stream_last_errors(); +if (!empty($errors)) { + $error = $errors[0]; echo "Is I/O error: " . ($error->code->isIoError() ? 'yes' : 'no') . "\n"; echo "Is filesystem error: " . ($error->code->isFileSystemError() ? 'yes' : 'no') . "\n"; echo "Is network error: " . ($error->code->isNetworkError() ? 'yes' : 'no') . "\n"; diff --git a/ext/standard/tests/streams/stream_errors_error_has_code.phpt b/ext/standard/tests/streams/stream_errors_error_has_code.phpt index 2bd9595f67876..6cd6b70411a6f 100644 --- a/ext/standard/tests/streams/stream_errors_error_has_code.phpt +++ b/ext/standard/tests/streams/stream_errors_error_has_code.phpt @@ -12,11 +12,11 @@ $context = stream_context_create([ // First operation $stream1 = fopen('php://nonexistent1', 'r', false, $context); -$error1 = stream_get_last_error(); +$error1 = stream_last_errors()[0]; // Second operation $stream2 = fopen('php://nonexistent2', 'r', false, $context); -$error2 = stream_get_last_error(); +$error2 = stream_last_errors()[0]; // Should get the most recent error (second operation) if ($error2) { diff --git a/ext/standard/tests/streams/stream_errors_exception_mode_terminal.phpt b/ext/standard/tests/streams/stream_errors_exception_mode_terminal.phpt index f3aaf1153db9e..37f5d39bfa759 100644 --- a/ext/standard/tests/streams/stream_errors_exception_mode_terminal.phpt +++ b/ext/standard/tests/streams/stream_errors_exception_mode_terminal.phpt @@ -15,8 +15,9 @@ try { echo "Caught: " . $e->getMessage() . "\n"; echo "Code: " . $e->getCode() . "\n"; - $error = $e->getError(); - if ($error) { + $errors = $e->getErrors(); + if (!empty($errors)) { + $error = $errors[0]; echo "Wrapper: " . $error->wrapperName . "\n"; echo "Error code name: " . $error->code->name . "\n"; } diff --git a/ext/standard/tests/streams/stream_errors_mix_modes_storage.phpt b/ext/standard/tests/streams/stream_errors_mix_modes_storage.phpt index d7c8f51669300..49c18616dad3f 100644 --- a/ext/standard/tests/streams/stream_errors_mix_modes_storage.phpt +++ b/ext/standard/tests/streams/stream_errors_mix_modes_storage.phpt @@ -28,6 +28,7 @@ class TestStream { stream_wrapper_register('test', 'TestStream'); function stream_test_errors($title, $contextOptions) { + stream_clear_errors(); $context = stream_context_create($contextOptions); $stream = fopen('test://foo', 'r', false, $context); try { @@ -43,22 +44,18 @@ function stream_test_errors($title, $contextOptions) { echo 'EXCEPTION: ' . $e->getMessage() . "\n"; } - $error = stream_get_last_error(); - if ($error) { + $errors = stream_last_errors(); + if ($errors) { + $first = $errors[0]; echo "Error details:\n"; - echo "- Message: $error->message\n"; - echo "- Code: " . $error->code->name . "\n"; - echo "- Wrapper: $error->wrapperName\n"; - echo "- Terminating: " . ($error->terminating ? 'yes' : 'no') . "\n"; - echo "- Count: " . $error->count() . "\n"; - - // Show all errors in chain - $current = $error; - $idx = 0; - while ($current) { - echo " [$idx] " . $current->code->name . ": " . $current->message . "\n"; - $current = $current->next; - $idx++; + echo "- Message: $first->message\n"; + echo "- Code: " . $first->code->name . "\n"; + echo "- Wrapper: $first->wrapperName\n"; + echo "- Terminating: " . ($first->terminating ? 'yes' : 'no') . "\n"; + echo "- Count: " . count($errors) . "\n"; + + foreach ($errors as $idx => $error) { + echo " [$idx] " . $error->code->name . ": " . $error->message . "\n"; } } else { echo "No errors stored\n"; @@ -149,10 +146,4 @@ Warning: fread(): TestStream::stream_read - read 10 bytes more data than request Warning: stream_select(): TestStream::stream_cast is not implemented! in %s on line %d Warning: stream_select(): Cannot represent a stream of type user-space as a select()able descriptor in %s on line %d -Error details: -- Message: TestStream::stream_read - read 10 bytes more data than requested (8202 read, 8192 max) - excess data will be lost -- Code: UserspaceInvalidReturn -- Wrapper: user-space -- Terminating: no -- Count: 1 - [0] UserspaceInvalidReturn: TestStream::stream_read - read 10 bytes more data than requested (8202 read, 8192 max) - excess data will be lost +No errors stored diff --git a/ext/standard/tests/streams/stream_errors_modes_with_auto_store.phpt b/ext/standard/tests/streams/stream_errors_modes_with_auto_store.phpt index cfc776c437db2..2575a8a795f99 100644 --- a/ext/standard/tests/streams/stream_errors_modes_with_auto_store.phpt +++ b/ext/standard/tests/streams/stream_errors_modes_with_auto_store.phpt @@ -12,8 +12,8 @@ $context1 = stream_context_create([ ]); @fopen('php://nonexistent', 'r', false, $context1); -$error1 = stream_get_last_error(); -echo "ERROR mode AUTO: " . ($error1 ? "has error" : "no error") . "\n"; +$errors1 = stream_last_errors(); +echo "ERROR mode AUTO: " . (!empty($errors1) ? "has error" : "no error") . "\n"; // AUTO with EXCEPTION mode should store NON_TERM $context2 = stream_context_create([ @@ -27,8 +27,8 @@ try { fopen('php://nonexistent2', 'r', false, $context2); } catch (StreamException $e) {} -$error2 = stream_get_last_error(); -echo "EXCEPTION mode AUTO: " . ($error2 ? "has error" : "no error") . "\n"; +$errors2 = stream_last_errors(); +echo "EXCEPTION mode AUTO: " . (!empty($errors2) ? "has error" : "no error") . "\n"; // AUTO with SILENT mode should store ALL $context3 = stream_context_create([ @@ -39,8 +39,8 @@ $context3 = stream_context_create([ ]); fopen('php://nonexistent3', 'r', false, $context3); -$error3 = stream_get_last_error(); -echo "SILENT mode AUTO: " . ($error3 ? "has error" : "no error") . "\n"; +$errors3 = stream_last_errors(); +echo "SILENT mode AUTO: " . (!empty($errors3) ? "has error" : "no error") . "\n"; ?> --EXPECTF-- diff --git a/ext/standard/tests/streams/stream_errors_multi_store.phpt b/ext/standard/tests/streams/stream_errors_multi_store.phpt deleted file mode 100644 index eccfb065d563c..0000000000000 --- a/ext/standard/tests/streams/stream_errors_multi_store.phpt +++ /dev/null @@ -1,23 +0,0 @@ ---TEST-- -Stream errors - StreamError hasCode method ---FILE-- - [ - 'error_mode' => StreamErrorMode::Silent, - ] -]); - -$stream = fopen('php://nonexistent', 'r', false, $context); - -$error = stream_get_last_error(); -if ($error) { - echo "Has OpenFailed: " . ($error->hasCode(StreamErrorCode::OpenFailed) ? 'yes' : 'no') . "\n"; - echo "Has NotFound: " . ($error->hasCode(StreamErrorCode::NotFound) ? 'yes' : 'no') . "\n"; -} - -?> ---EXPECT-- -Has OpenFailed: yes -Has NotFound: no diff --git a/ext/standard/tests/streams/stream_errors_silent_with_handler.phpt b/ext/standard/tests/streams/stream_errors_silent_with_handler.phpt index 2416a15529aa5..456575affc3a1 100644 --- a/ext/standard/tests/streams/stream_errors_silent_with_handler.phpt +++ b/ext/standard/tests/streams/stream_errors_silent_with_handler.phpt @@ -8,14 +8,16 @@ $handler_called = false; $context = stream_context_create([ 'stream' => [ 'error_mode' => StreamErrorMode::Silent, - 'error_handler' => function(StreamError $error) use (&$handler_called) { + 'error_handler' => function(array $errors) use (&$handler_called) { $handler_called = true; echo "Handler called\n"; - echo "Wrapper: " . $error->wrapperName . "\n"; - echo "Code: " . $error->code->name . "\n"; - echo "Message: " . $error->message . "\n"; - echo "Param: " . ($error->param ?? 'null') . "\n"; - echo "Terminating: " . ($error->terminating ? 'yes' : 'no') . "\n"; + foreach ($errors as $error) { + echo "Wrapper: " . $error->wrapperName . "\n"; + echo "Code: " . $error->code->name . "\n"; + echo "Message: " . $error->message . "\n"; + echo "Param: " . ($error->param ?? 'null') . "\n"; + echo "Terminating: " . ($error->terminating ? 'yes' : 'no') . "\n"; + } } ] ]); diff --git a/ext/standard/tests/streams/stream_errors_silent_with_storage.phpt b/ext/standard/tests/streams/stream_errors_silent_with_storage.phpt index 0d3d627001788..9e356216b0dd9 100644 --- a/ext/standard/tests/streams/stream_errors_silent_with_storage.phpt +++ b/ext/standard/tests/streams/stream_errors_silent_with_storage.phpt @@ -12,8 +12,8 @@ $context = stream_context_create([ $stream = fopen('php://nonexistent', 'r', false, $context); var_dump($stream); -$error = stream_get_last_error(); -if ($error) { +$errors = stream_last_errors(); +foreach ($errors as $error) { echo "Has error: yes\n"; echo "Error code: " . $error->code->name . "\n"; echo "Error wrapper: " . $error->wrapperName . "\n"; diff --git a/ext/standard/tests/streams/stream_errors_silent_without_storage.phpt b/ext/standard/tests/streams/stream_errors_silent_without_storage.phpt index 477bbd7401c26..8155ce60bfee9 100644 --- a/ext/standard/tests/streams/stream_errors_silent_without_storage.phpt +++ b/ext/standard/tests/streams/stream_errors_silent_without_storage.phpt @@ -12,8 +12,8 @@ $context = stream_context_create([ $stream = fopen('php://nonexistent', 'r', false, $context); -$error = stream_get_last_error(); -echo "Has error: " . ($error ? "yes" : "no") . "\n"; +$errors = stream_last_errors(); +echo "Has error: " . (!empty($error) ? "yes" : "no") . "\n"; ?> --EXPECT-- diff --git a/main/streams/php_stream_errors.h b/main/streams/php_stream_errors.h index 7bcafa779984c..c55c06e37f25a 100644 --- a/main/streams/php_stream_errors.h +++ b/main/streams/php_stream_errors.h @@ -70,7 +70,7 @@ BEGIN_EXTERN_C() #define PHP_STREAM_ERROR_WRAPPER_NAME(_wrapper) \ (_wrapper ? _wrapper->wops->label : PHP_STREAM_ERROR_WRAPPER_DEFAULT_NAME) -/* Error entry in chain */ +/* Error entry in chain (internal linked list) */ typedef struct _php_stream_error_entry { zend_string *message; zend_enum_StreamErrorCode code; @@ -92,6 +92,7 @@ typedef struct _php_stream_error_operation { /* Stored completed operation */ typedef struct _php_stream_stored_error { php_stream_error_entry *first_error; + uint32_t error_count; struct _php_stream_stored_error *next; } php_stream_stored_error; @@ -114,8 +115,11 @@ PHPAPI void php_stream_error_operation_abort(void); /* State cleanup function */ PHPAPI void php_stream_error_state_cleanup(void); -/* Error object creation */ -PHPAPI void php_stream_error_create_object(zval *zv, php_stream_error_entry *entry); +/* Retrieve last stored errors as array of StreamError objects */ +PHPAPI void php_stream_error_get_last(zval *return_value); + +/* Clear all stored errors */ +PHPAPI void php_stream_error_clear_stored(void); /* Wrapper error reporting functions */ PHPAPI void php_stream_wrapper_error_with_name(const char *wrapper_name, diff --git a/main/streams/stream_errors.c b/main/streams/stream_errors.c index 76bf612221f99..cec595ea32b0f 100644 --- a/main/streams/stream_errors.c +++ b/main/streams/stream_errors.c @@ -14,7 +14,7 @@ +----------------------------------------------------------------------+ */ -#define ZEND_ENUM_StreamErrorCode_USE_NAME_TABLE 1 +#define ZEND_ENUM_StreamErrorCode_USE_NAME_TABLE #include "php.h" #include "php_globals.h" #include "php_streams.h" @@ -35,6 +35,62 @@ static zend_class_entry *php_ce_stream_exception; static void php_stream_error_entry_free(php_stream_error_entry *entry); static bool php_stream_error_code_in_range(zval *this_zv, int start, int end); +/* Helper to create a single StreamError object from an entry */ +static void php_stream_error_create_object(zval *zv, php_stream_error_entry *entry) +{ + object_init_ex(zv, php_ce_stream_error); + + const char *case_name = NULL; + if (entry->code > 0 && entry->code <= ZEND_ENUM_StreamErrorCode_CASE_COUNT) { + case_name = zend_enum_StreamErrorCode_case_names[entry->code]; + } + if (!case_name) { + case_name = "Generic"; + } + + zend_object *enum_obj = zend_enum_get_case_cstr(php_ce_stream_error_code, case_name); + ZEND_ASSERT(enum_obj != NULL); + + zval code_enum; + ZVAL_OBJ_COPY(&code_enum, enum_obj); + + zend_update_property(php_ce_stream_error, Z_OBJ_P(zv), ZEND_STRL("code"), &code_enum); + zval_ptr_dtor(&code_enum); + + zend_update_property_str( + php_ce_stream_error, Z_OBJ_P(zv), ZEND_STRL("message"), entry->message); + + zend_update_property_string(php_ce_stream_error, Z_OBJ_P(zv), ZEND_STRL("wrapperName"), + entry->wrapper_name ? entry->wrapper_name : ""); + + zend_update_property_long( + php_ce_stream_error, Z_OBJ_P(zv), ZEND_STRL("severity"), entry->severity); + + zend_update_property_bool( + php_ce_stream_error, Z_OBJ_P(zv), ZEND_STRL("terminating"), entry->terminating); + + if (entry->param) { + zend_update_property_string( + php_ce_stream_error, Z_OBJ_P(zv), ZEND_STRL("param"), entry->param); + } else { + zend_update_property_null(php_ce_stream_error, Z_OBJ_P(zv), ZEND_STRL("param")); + } +} + +/* Create array of StreamError objects from error chain */ +PHPAPI void php_stream_error_create_array(zval *zv, php_stream_error_entry *first) +{ + array_init(zv); + + php_stream_error_entry *entry = first; + while (entry) { + zval error_obj; + php_stream_error_create_object(&error_obj, entry); + zend_hash_next_index_insert_new(Z_ARRVAL_P(zv), &error_obj); + entry = entry->next; + } +} + /* Context option helpers */ static int php_stream_auto_decide_error_store_mode(int error_mode) @@ -200,6 +256,34 @@ PHPAPI void php_stream_error_state_cleanup(void) } } +PHPAPI void php_stream_error_get_last(zval *return_value) +{ + php_stream_error_state *state = &FG(stream_error_state); + + if (!state->stored_errors) { + ZVAL_EMPTY_ARRAY(return_value); + return; + } + + php_stream_error_create_array(return_value, state->stored_errors->first_error); +} + +PHPAPI void php_stream_error_clear_stored(void) +{ + php_stream_error_state *state = &FG(stream_error_state); + + php_stream_stored_error *stored = state->stored_errors; + while (stored) { + php_stream_stored_error *next = stored->next; + php_stream_error_entry_free(stored->first_error); + efree(stored); + stored = next; + } + + state->stored_errors = NULL; + state->stored_count = 0; +} + /* Error operation stack management */ PHPAPI php_stream_error_operation *php_stream_error_operation_begin(void) @@ -269,7 +353,7 @@ static void php_stream_error_add(zend_enum_StreamErrorCode code, const char *wra /* Error reporting */ -static void php_stream_call_error_handler(zval *handler, zval *error_obj) +static void php_stream_call_error_handler(zval *handler, zval *errors_array) { zend_fcall_info_cache fcc; char *is_callable_error = NULL; @@ -284,7 +368,7 @@ static void php_stream_call_error_handler(zval *handler, zval *error_obj) zval retval; - call_user_function(NULL, NULL, handler, &retval, 1, error_obj); + call_user_function(NULL, NULL, handler, &retval, 1, errors_array); zval_ptr_dtor(&retval); } @@ -295,21 +379,23 @@ static void php_stream_throw_exception_with_errors(php_stream_error_operation *o return; } - zval error_obj; - php_stream_error_create_object(&error_obj, op->first_error); - zval ex; object_init_ex(&ex, php_ce_stream_exception); + /* Set message from first error */ zend_update_property_string(php_ce_stream_exception, Z_OBJ(ex), ZEND_STRL("message"), ZSTR_VAL(op->first_error->message)); + /* Set code from first error */ zend_update_property_long(php_ce_stream_exception, Z_OBJ(ex), ZEND_STRL("code"), (zend_long) op->first_error->code); - zend_update_property(php_ce_stream_exception, Z_OBJ(ex), ZEND_STRL("error"), &error_obj); + /* Build errors array and set it */ + zval errors_array; + php_stream_error_create_array(&errors_array, op->first_error); + zend_update_property(php_ce_stream_exception, Z_OBJ(ex), ZEND_STRL("errors"), &errors_array); + zval_ptr_dtor(&errors_array); - zval_ptr_dtor(&error_obj); zend_throw_exception_object(&ex); } @@ -343,16 +429,17 @@ static void php_stream_report_errors(php_stream_context *context, php_stream_err break; } + /* Call user error handler if set */ zval *handler = context ? php_stream_context_get_option(context, "stream", "error_handler") : NULL; if (handler) { - zval error_obj; - php_stream_error_create_object(&error_obj, op->first_error); + zval errors_array; + php_stream_error_create_array(&errors_array, op->first_error); - php_stream_call_error_handler(handler, &error_obj); + php_stream_call_error_handler(handler, &errors_array); - zval_ptr_dtor(&error_obj); + zval_ptr_dtor(&errors_array); } } @@ -390,6 +477,7 @@ PHPAPI void php_stream_error_operation_end(php_stream_context *context) php_stream_error_entry *prev = NULL; php_stream_error_entry *to_store_first = NULL; php_stream_error_entry *to_store_last = NULL; + uint32_t to_store_count = 0; php_stream_error_entry *remaining_first = NULL; while (entry) { @@ -412,6 +500,7 @@ PHPAPI void php_stream_error_operation_end(php_stream_context *context) to_store_first = entry; } to_store_last = entry; + to_store_count++; } else { entry->next = NULL; if (prev) { @@ -428,6 +517,7 @@ PHPAPI void php_stream_error_operation_end(php_stream_context *context) if (to_store_first) { php_stream_stored_error *stored = emalloc(sizeof(php_stream_stored_error)); stored->first_error = to_store_first; + stored->error_count = to_store_count; stored->next = state->stored_errors; state->stored_errors = stored; @@ -800,123 +890,16 @@ PHPAPI void php_stream_tidy_wrapper_error_log(php_stream_wrapper *wrapper) } } -PHPAPI void php_stream_error_create_object(zval *zv, php_stream_error_entry *entry) -{ - if (!entry) { - ZVAL_NULL(zv); - return; - } - - object_init_ex(zv, php_ce_stream_error); - - const char *case_name = NULL; - if (entry->code > 0 && entry->code <= ZEND_ENUM_StreamErrorCode_CASE_COUNT) { - case_name = zend_enum_StreamErrorCode_case_names[entry->code]; - } - if (!case_name) { - case_name = "Generic"; - } - - zend_object *enum_obj = zend_enum_get_case_cstr(php_ce_stream_error_code, case_name); - ZEND_ASSERT(enum_obj != NULL); - - zval code_enum; - ZVAL_OBJ_COPY(&code_enum, enum_obj); - - zend_update_property(php_ce_stream_error, Z_OBJ_P(zv), ZEND_STRL("code"), &code_enum); - zval_ptr_dtor(&code_enum); - - zend_update_property_str( - php_ce_stream_error, Z_OBJ_P(zv), ZEND_STRL("message"), entry->message); - - zend_update_property_string(php_ce_stream_error, Z_OBJ_P(zv), ZEND_STRL("wrapperName"), - entry->wrapper_name ? entry->wrapper_name : ""); - - zend_update_property_long( - php_ce_stream_error, Z_OBJ_P(zv), ZEND_STRL("severity"), entry->severity); - - zend_update_property_bool( - php_ce_stream_error, Z_OBJ_P(zv), ZEND_STRL("terminating"), entry->terminating); - - if (entry->param) { - zend_update_property_string( - php_ce_stream_error, Z_OBJ_P(zv), ZEND_STRL("param"), entry->param); - } else { - zend_update_property_null(php_ce_stream_error, Z_OBJ_P(zv), ZEND_STRL("param")); - } - - if (entry->next) { - zval next_error; - php_stream_error_create_object(&next_error, entry->next); - zend_update_property(php_ce_stream_error, Z_OBJ_P(zv), ZEND_STRL("next"), &next_error); - zval_ptr_dtor(&next_error); - } else { - zend_update_property_null(php_ce_stream_error, Z_OBJ_P(zv), ZEND_STRL("next")); - } -} - -/* StreamError methods */ - -PHP_METHOD(StreamError, hasCode) -{ - zval *search_code; - - ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_OBJECT_OF_CLASS(search_code, php_ce_stream_error_code) - ZEND_PARSE_PARAMETERS_END(); - - zval *current_error_zv = ZEND_THIS; - - while (Z_TYPE_P(current_error_zv) == IS_OBJECT) { - zval *code_zv = zend_read_property( - php_ce_stream_error, Z_OBJ_P(current_error_zv), ZEND_STRL("code"), 1, NULL); - - if (Z_TYPE_P(code_zv) == IS_OBJECT && Z_OBJ_P(code_zv) == Z_OBJ_P(search_code)) { - RETURN_TRUE; - } - - current_error_zv = zend_read_property( - php_ce_stream_error, Z_OBJ_P(current_error_zv), ZEND_STRL("next"), 1, NULL); - - if (Z_TYPE_P(current_error_zv) != IS_OBJECT) { - break; - } - } - - RETURN_FALSE; -} - -PHP_METHOD(StreamError, count) -{ - ZEND_PARSE_PARAMETERS_NONE(); - - zend_long count = 1; - zval *current_error_zv = ZEND_THIS; - - while (1) { - current_error_zv = zend_read_property( - php_ce_stream_error, Z_OBJ_P(current_error_zv), ZEND_STRL("next"), 1, NULL); - - if (Z_TYPE_P(current_error_zv) != IS_OBJECT) { - break; - } - - count++; - } - - RETURN_LONG(count); -} - /* StreamException methods */ -PHP_METHOD(StreamException, getError) +PHP_METHOD(StreamException, getErrors) { ZEND_PARSE_PARAMETERS_NONE(); - zval *error = zend_read_property( - php_ce_stream_exception, Z_OBJ_P(ZEND_THIS), ZEND_STRL("error"), 1, NULL); + zval *errors = zend_read_property( + php_ce_stream_exception, Z_OBJ_P(ZEND_THIS), ZEND_STRL("errors"), 1, NULL); - RETURN_COPY(error); + RETURN_COPY(errors); } /* StreamErrorCode range helpers - case_id based */ diff --git a/main/streams/stream_errors.stub.php b/main/streams/stream_errors.stub.php index 3540ff6f461fb..3c211b008c820 100644 --- a/main/streams/stream_errors.stub.php +++ b/main/streams/stream_errors.stub.php @@ -151,16 +151,13 @@ enum StreamErrorStore public int $severity; public bool $terminating; public ?string $param; - public ?StreamError $next; - - public function hasCode(StreamErrorCode $code): bool {} - - public function count(): int {} } class StreamException extends Exception { - private ?StreamError $error = null; + /** @var list */ + private array $errors = []; - public function getError(): ?StreamError {} + /** @return list */ + public function getErrors(): array {} } diff --git a/main/streams/stream_errors_arginfo.h b/main/streams/stream_errors_arginfo.h index 7de77e9c4e296..4936417354a69 100644 --- a/main/streams/stream_errors_arginfo.h +++ b/main/streams/stream_errors_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit stream_errors.stub.php instead. - * Stub hash: 40c314c471a8fb600bbf219e96a31cec8590eb4a + * Stub hash: 9e4dc19314a34c3d07fbe013c7cabccefec4922d * Has decl header: yes */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_StreamErrorCode_isIoError, 0, 0, _IS_BOOL, 0) @@ -23,14 +23,7 @@ ZEND_END_ARG_INFO() #define arginfo_class_StreamErrorCode_isUserspaceError arginfo_class_StreamErrorCode_isIoError -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_StreamError_hasCode, 0, 1, _IS_BOOL, 0) - ZEND_ARG_OBJ_INFO(0, code, StreamErrorCode, 0) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_StreamError_count, 0, 0, IS_LONG, 0) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_StreamException_getError, 0, 0, StreamError, 1) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_StreamException_getErrors, 0, 0, IS_ARRAY, 0) ZEND_END_ARG_INFO() static ZEND_METHOD(StreamErrorCode, isIoError); @@ -43,9 +36,7 @@ static ZEND_METHOD(StreamErrorCode, isEncodingError); static ZEND_METHOD(StreamErrorCode, isResourceError); static ZEND_METHOD(StreamErrorCode, isLockError); static ZEND_METHOD(StreamErrorCode, isUserspaceError); -static ZEND_METHOD(StreamError, hasCode); -static ZEND_METHOD(StreamError, count); -static ZEND_METHOD(StreamException, getError); +static ZEND_METHOD(StreamException, getErrors); static const zend_function_entry class_StreamErrorCode_methods[] = { ZEND_ME(StreamErrorCode, isIoError, arginfo_class_StreamErrorCode_isIoError, ZEND_ACC_PUBLIC) @@ -61,14 +52,8 @@ static const zend_function_entry class_StreamErrorCode_methods[] = { ZEND_FE_END }; -static const zend_function_entry class_StreamError_methods[] = { - ZEND_ME(StreamError, hasCode, arginfo_class_StreamError_hasCode, ZEND_ACC_PUBLIC) - ZEND_ME(StreamError, count, arginfo_class_StreamError_count, ZEND_ACC_PUBLIC) - ZEND_FE_END -}; - static const zend_function_entry class_StreamException_methods[] = { - ZEND_ME(StreamException, getError, arginfo_class_StreamException_getError, ZEND_ACC_PUBLIC) + ZEND_ME(StreamException, getErrors, arginfo_class_StreamException_getErrors, ZEND_ACC_PUBLIC) ZEND_FE_END }; @@ -265,7 +250,7 @@ static zend_class_entry *register_class_StreamError(void) { zend_class_entry ce, *class_entry; - INIT_CLASS_ENTRY(ce, "StreamError", class_StreamError_methods); + INIT_CLASS_ENTRY(ce, "StreamError", NULL); class_entry = zend_register_internal_class_with_flags(&ce, NULL, ZEND_ACC_FINAL|ZEND_ACC_READONLY_CLASS); zval property_code_default_value; @@ -299,13 +284,6 @@ static zend_class_entry *register_class_StreamError(void) zend_declare_typed_property(class_entry, property_param_name, &property_param_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING|MAY_BE_NULL)); zend_string_release_ex(property_param_name, true); - zval property_next_default_value; - ZVAL_UNDEF(&property_next_default_value); - zend_string *property_next_name = zend_string_init("next", sizeof("next") - 1, true); - zend_string *property_next_class_StreamError = zend_string_init("StreamError", sizeof("StreamError")-1, 1); - zend_declare_typed_property(class_entry, property_next_name, &property_next_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_CLASS(property_next_class_StreamError, 0, MAY_BE_NULL)); - zend_string_release_ex(property_next_name, true); - return class_entry; } @@ -316,12 +294,11 @@ static zend_class_entry *register_class_StreamException(zend_class_entry *class_ INIT_CLASS_ENTRY(ce, "StreamException", class_StreamException_methods); class_entry = zend_register_internal_class_with_flags(&ce, class_entry_Exception, 0); - zval property_error_default_value; - ZVAL_NULL(&property_error_default_value); - zend_string *property_error_name = zend_string_init("error", sizeof("error") - 1, true); - zend_string *property_error_class_StreamError = zend_string_init("StreamError", sizeof("StreamError")-1, 1); - zend_declare_typed_property(class_entry, property_error_name, &property_error_default_value, ZEND_ACC_PRIVATE, NULL, (zend_type) ZEND_TYPE_INIT_CLASS(property_error_class_StreamError, 0, MAY_BE_NULL)); - zend_string_release_ex(property_error_name, true); + zval property_errors_default_value; + ZVAL_EMPTY_ARRAY(&property_errors_default_value); + zend_string *property_errors_name = zend_string_init("errors", sizeof("errors") - 1, true); + zend_declare_typed_property(class_entry, property_errors_name, &property_errors_default_value, ZEND_ACC_PRIVATE, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_ARRAY)); + zend_string_release_ex(property_errors_name, true); return class_entry; } diff --git a/main/streams/stream_errors_decl.h b/main/streams/stream_errors_decl.h index 16939a9037258..9ba2697e0a95f 100644 --- a/main/streams/stream_errors_decl.h +++ b/main/streams/stream_errors_decl.h @@ -1,8 +1,8 @@ /* This is a generated file, edit stream_errors.stub.php instead. - * Stub hash: 40c314c471a8fb600bbf219e96a31cec8590eb4a */ + * Stub hash: 9e4dc19314a34c3d07fbe013c7cabccefec4922d */ -#ifndef ZEND_STREAM_ERRORS_DECL_40c314c471a8fb600bbf219e96a31cec8590eb4a_H -#define ZEND_STREAM_ERRORS_DECL_40c314c471a8fb600bbf219e96a31cec8590eb4a_H +#ifndef ZEND_STREAM_ERRORS_DECL_9e4dc19314a34c3d07fbe013c7cabccefec4922d_H +#define ZEND_STREAM_ERRORS_DECL_9e4dc19314a34c3d07fbe013c7cabccefec4922d_H typedef enum zend_enum_StreamErrorCode { ZEND_ENUM_StreamErrorCode_None = 1, @@ -180,4 +180,4 @@ typedef enum zend_enum_StreamErrorStore { ZEND_ENUM_StreamErrorStore_All = 5, } zend_enum_StreamErrorStore; -#endif /* ZEND_STREAM_ERRORS_DECL_40c314c471a8fb600bbf219e96a31cec8590eb4a_H */ +#endif /* ZEND_STREAM_ERRORS_DECL_9e4dc19314a34c3d07fbe013c7cabccefec4922d_H */ From 8dce66c3c1b30b34f2e117593880b85ad4066725 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Sun, 29 Mar 2026 20:13:09 +0200 Subject: [PATCH 67/68] stream: fix optimizer info for stream_last_errors --- Zend/Optimizer/zend_func_infos.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Zend/Optimizer/zend_func_infos.h b/Zend/Optimizer/zend_func_infos.h index 86d7f478fe111..cc1a9afd19ea8 100644 --- a/Zend/Optimizer/zend_func_infos.h +++ b/Zend/Optimizer/zend_func_infos.h @@ -596,7 +596,7 @@ static const func_info_t func_infos[] = { F1("stream_get_line", MAY_BE_STRING|MAY_BE_FALSE), F1("stream_resolve_include_path", MAY_BE_STRING|MAY_BE_FALSE), F1("stream_get_wrappers", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_OF_STRING), - F1("stream_get_last_error", MAY_BE_OBJECT|MAY_BE_NULL), + F1("stream_last_errors", MAY_BE_OBJECT), F1("stream_get_transports", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_OF_STRING), #if defined(HAVE_GETTIMEOFDAY) F1("uniqid", MAY_BE_STRING), From b033defc73803a96ccd0d36a774e2d2d82b3a375 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Sun, 29 Mar 2026 23:18:24 +0200 Subject: [PATCH 68/68] stream: fix errors function types --- Zend/Optimizer/zend_func_infos.h | 2 +- ext/standard/basic_functions.stub.php | 2 +- ext/standard/basic_functions_arginfo.h | 2 +- ext/standard/basic_functions_decl.h | 8 ++++---- main/streams/stream_errors.stub.php | 4 ++-- main/streams/stream_errors_arginfo.h | 2 +- main/streams/stream_errors_decl.h | 8 ++++---- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Zend/Optimizer/zend_func_infos.h b/Zend/Optimizer/zend_func_infos.h index cc1a9afd19ea8..b76785283dc5c 100644 --- a/Zend/Optimizer/zend_func_infos.h +++ b/Zend/Optimizer/zend_func_infos.h @@ -596,7 +596,7 @@ static const func_info_t func_infos[] = { F1("stream_get_line", MAY_BE_STRING|MAY_BE_FALSE), F1("stream_resolve_include_path", MAY_BE_STRING|MAY_BE_FALSE), F1("stream_get_wrappers", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_OF_STRING), - F1("stream_last_errors", MAY_BE_OBJECT), + F1("stream_last_errors", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_OF_OBJECT), F1("stream_get_transports", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_OF_STRING), #if defined(HAVE_GETTIMEOFDAY) F1("uniqid", MAY_BE_STRING), diff --git a/ext/standard/basic_functions.stub.php b/ext/standard/basic_functions.stub.php index 1a5146637a77e..e587b9c30636e 100644 --- a/ext/standard/basic_functions.stub.php +++ b/ext/standard/basic_functions.stub.php @@ -3556,7 +3556,7 @@ function stream_get_wrappers(): array {} /** * @refcount 1 - * @return list + * @return array */ function stream_last_errors(): array {} diff --git a/ext/standard/basic_functions_arginfo.h b/ext/standard/basic_functions_arginfo.h index 29046f7bf5629..7e460fbdf699b 100644 --- a/ext/standard/basic_functions_arginfo.h +++ b/ext/standard/basic_functions_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit basic_functions.stub.php instead. - * Stub hash: b824f606ebb1daf1ad8df828bfdbf0c9ae985630 + * Stub hash: 426cf6f68840941b614915fe566021802bb12abe * Has decl header: yes */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_set_time_limit, 0, 1, _IS_BOOL, 0) diff --git a/ext/standard/basic_functions_decl.h b/ext/standard/basic_functions_decl.h index 640dfeb20d0ac..d29b658012501 100644 --- a/ext/standard/basic_functions_decl.h +++ b/ext/standard/basic_functions_decl.h @@ -1,8 +1,8 @@ /* This is a generated file, edit basic_functions.stub.php instead. - * Stub hash: b824f606ebb1daf1ad8df828bfdbf0c9ae985630 */ + * Stub hash: 426cf6f68840941b614915fe566021802bb12abe */ -#ifndef ZEND_BASIC_FUNCTIONS_DECL_b824f606ebb1daf1ad8df828bfdbf0c9ae985630_H -#define ZEND_BASIC_FUNCTIONS_DECL_b824f606ebb1daf1ad8df828bfdbf0c9ae985630_H +#ifndef ZEND_BASIC_FUNCTIONS_DECL_426cf6f68840941b614915fe566021802bb12abe_H +#define ZEND_BASIC_FUNCTIONS_DECL_426cf6f68840941b614915fe566021802bb12abe_H typedef enum zend_enum_RoundingMode { ZEND_ENUM_RoundingMode_HalfAwayFromZero = 1, @@ -15,4 +15,4 @@ typedef enum zend_enum_RoundingMode { ZEND_ENUM_RoundingMode_PositiveInfinity = 8, } zend_enum_RoundingMode; -#endif /* ZEND_BASIC_FUNCTIONS_DECL_b824f606ebb1daf1ad8df828bfdbf0c9ae985630_H */ +#endif /* ZEND_BASIC_FUNCTIONS_DECL_426cf6f68840941b614915fe566021802bb12abe_H */ diff --git a/main/streams/stream_errors.stub.php b/main/streams/stream_errors.stub.php index 3c211b008c820..a3508f1eb76c0 100644 --- a/main/streams/stream_errors.stub.php +++ b/main/streams/stream_errors.stub.php @@ -155,9 +155,9 @@ enum StreamErrorStore class StreamException extends Exception { - /** @var list */ + /** @var array */ private array $errors = []; - /** @return list */ + /** @return array */ public function getErrors(): array {} } diff --git a/main/streams/stream_errors_arginfo.h b/main/streams/stream_errors_arginfo.h index 4936417354a69..cfa4e5a44b539 100644 --- a/main/streams/stream_errors_arginfo.h +++ b/main/streams/stream_errors_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit stream_errors.stub.php instead. - * Stub hash: 9e4dc19314a34c3d07fbe013c7cabccefec4922d + * Stub hash: 65d3a47368993358ac8a4a41bc93dbff5677d3f5 * Has decl header: yes */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_StreamErrorCode_isIoError, 0, 0, _IS_BOOL, 0) diff --git a/main/streams/stream_errors_decl.h b/main/streams/stream_errors_decl.h index 9ba2697e0a95f..e29bd21f376e5 100644 --- a/main/streams/stream_errors_decl.h +++ b/main/streams/stream_errors_decl.h @@ -1,8 +1,8 @@ /* This is a generated file, edit stream_errors.stub.php instead. - * Stub hash: 9e4dc19314a34c3d07fbe013c7cabccefec4922d */ + * Stub hash: 65d3a47368993358ac8a4a41bc93dbff5677d3f5 */ -#ifndef ZEND_STREAM_ERRORS_DECL_9e4dc19314a34c3d07fbe013c7cabccefec4922d_H -#define ZEND_STREAM_ERRORS_DECL_9e4dc19314a34c3d07fbe013c7cabccefec4922d_H +#ifndef ZEND_STREAM_ERRORS_DECL_65d3a47368993358ac8a4a41bc93dbff5677d3f5_H +#define ZEND_STREAM_ERRORS_DECL_65d3a47368993358ac8a4a41bc93dbff5677d3f5_H typedef enum zend_enum_StreamErrorCode { ZEND_ENUM_StreamErrorCode_None = 1, @@ -180,4 +180,4 @@ typedef enum zend_enum_StreamErrorStore { ZEND_ENUM_StreamErrorStore_All = 5, } zend_enum_StreamErrorStore; -#endif /* ZEND_STREAM_ERRORS_DECL_9e4dc19314a34c3d07fbe013c7cabccefec4922d_H */ +#endif /* ZEND_STREAM_ERRORS_DECL_65d3a47368993358ac8a4a41bc93dbff5677d3f5_H */