Commit d75f79e2acf for php.net
commit d75f79e2acfb28511923f90647ae7908933feb04
Author: Gina Peter Banyard <girgias@php.net>
Date: Mon Jul 20 22:17:04 2026 +0100
streams: refactor _php_stream_open_wrapper_ex() to use early returns
diff --git a/main/streams/streams.c b/main/streams/streams.c
index 740a1d7a6e0..3ec92b2a221 100644
--- a/main/streams/streams.c
+++ b/main/streams/streams.c
@@ -2118,14 +2118,28 @@ PHPAPI php_stream *_php_stream_open_wrapper_ex(const char *path, const char *mod
path_to_open = path;
wrapper = php_stream_locate_url_wrapper(path, &path_to_open, options);
- if ((options & STREAM_USE_URL) && (!wrapper || !wrapper->is_url)) {
- if (wrapper) {
- php_stream_wrapper_warn(wrapper, context, options,
- ProtocolUnsupported,
- "This function may only be used against URLs");
- } else {
- php_error_docref(NULL, E_WARNING, "This function may only be used against URLs");
+ if (UNEXPECTED(!wrapper)) {
+ php_stream_wrapper_warn_name(PHP_STREAM_ERROR_WRAPPER_DEFAULT_NAME, context, options, OpenFailed,
+ "Failed to open stream: no suitable wrapper could be found");
+ if (resolved_path) {
+ zend_string_release_ex(resolved_path, 0);
+ }
+ return NULL;
+ }
+ if ((options & STREAM_USE_URL) && !wrapper->is_url) {
+ php_stream_wrapper_warn(wrapper, context, options,
+ ProtocolUnsupported,
+ "This function may only be used against URLs");
+ if (resolved_path) {
+ zend_string_release_ex(resolved_path, 0);
}
+ return NULL;
+ }
+
+ if (!wrapper->wops->stream_opener) {
+ php_stream_wrapper_warn(wrapper, context, options,
+ NoOpener,
+ "wrapper does not support stream open");
if (resolved_path) {
zend_string_release_ex(resolved_path, 0);
}
@@ -2134,56 +2148,74 @@ PHPAPI php_stream *_php_stream_open_wrapper_ex(const char *path, const char *mod
/* 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,
- NoOpener,
- "wrapper does not support stream open");
- } else {
- stream = wrapper->wops->stream_opener(wrapper,
- path_to_open, mode, options & ~REPORT_ERRORS,
- opened_path, context STREAMS_REL_CC);
- }
+ stream = wrapper->wops->stream_opener(wrapper,
+ path_to_open, mode, options & ~REPORT_ERRORS,
+ opened_path, context STREAMS_REL_CC);
- /* 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_warn(wrapper, context, options & ~REPORT_ERRORS,
- PersistentNotSupported,
- "wrapper does not support persistent streams");
- php_stream_close(stream);
- stream = NULL;
+ if (UNEXPECTED(!stream)) {
+ if (options & REPORT_ERRORS) {
+ php_stream_display_wrapper_name_errors(wrapper_name, context, PHP_STREAM_EC(OpenFailed),
+ "Failed to open stream");
+ if (opened_path && *opened_path) {
+ zend_string_release_ex(*opened_path, 0);
+ *opened_path = NULL;
+ }
}
-
- if (stream) {
- stream->wrapper = wrapper;
+ php_stream_tidy_wrapper_name_error_log(wrapper_name);
+ pefree(wrapper_name, persistent);
+ if (resolved_path) {
+ zend_string_release_ex(resolved_path, 0);
}
+ return NULL;
}
- if (stream) {
- if (opened_path && !*opened_path && resolved_path) {
- *opened_path = resolved_path;
- resolved_path = NULL;
+ /* if the caller asked for a persistent stream but the wrapper did not
+ * return one, force an error here */
+ if (persistent && !stream->is_persistent) {
+ php_stream_wrapper_log_warn(wrapper, context, options & ~REPORT_ERRORS,
+ PersistentNotSupported,
+ "wrapper does not support persistent streams");
+ php_stream_close(stream);
+ if (options & REPORT_ERRORS) {
+ php_stream_display_wrapper_name_errors(wrapper_name, context, PHP_STREAM_EC(OpenFailed),
+ "Failed to open stream");
+ if (opened_path && *opened_path) {
+ zend_string_release_ex(*opened_path, 0);
+ *opened_path = NULL;
+ }
}
- if (stream->orig_path) {
- pefree(stream->orig_path, persistent);
+ php_stream_tidy_wrapper_name_error_log(wrapper_name);
+ pefree(wrapper_name, persistent);
+ if (resolved_path) {
+ zend_string_release_ex(resolved_path, 0);
}
- stream->orig_path = pestrdup(path, persistent);
+ return NULL;
+ }
+
+ stream->wrapper = wrapper;
+
+ if (opened_path && !*opened_path && resolved_path) {
+ *opened_path = resolved_path;
+ resolved_path = NULL;
+ }
+ if (stream->orig_path) {
+ pefree(stream->orig_path, persistent);
+ }
+ stream->orig_path = pestrdup(path, persistent);
#if ZEND_DEBUG
stream->open_filename = __zend_orig_filename ? __zend_orig_filename : __zend_filename;
stream->open_lineno = __zend_orig_lineno ? __zend_orig_lineno : __zend_lineno;
#endif
- /* Attach an explicitly provided context to the stream, but never the
- * default context: sharing it by reference would let a later
- * stream_context_set_option() on the stream mutate the global default
- * context, leaking options into every other stream. Stream errors fall
- * back to the default context on their own when the stream has none. */
- if (stream->ctx == NULL && context != NULL && context != FG(default_context) && !persistent) {
- php_stream_context_set(stream, context);
- }
+ /* Attach an explicitly provided context to the stream, but never the
+ * default context: sharing it by reference would let a later
+ * stream_context_set_option() on the stream mutate the global default
+ * context, leaking options into every other stream. Stream errors fall
+ * back to the default context on their own when the stream has none. */
+ if (stream->ctx == NULL && context != NULL && context != FG(default_context) && !persistent) {
+ php_stream_context_set(stream, context);
}
- if (stream != NULL && (options & STREAM_MUST_SEEK)) {
+ if (options & STREAM_MUST_SEEK) {
php_stream *newstream;
switch(php_stream_make_seekable_rel(stream, &newstream,
@@ -2207,16 +2239,19 @@ PHPAPI php_stream *_php_stream_open_wrapper_ex(const char *path, const char *mod
return newstream;
default:
php_stream_close(stream);
- stream = NULL;
php_stream_wrapper_warn(wrapper, context, options,
SeekNotSupported,
"could not make seekable - %s", path);
- /* We do not want multiple errors so we negate it */
- options &= ~REPORT_ERRORS;
+ php_stream_tidy_wrapper_name_error_log(wrapper_name);
+ pefree(wrapper_name, persistent);
+ if (resolved_path) {
+ zend_string_release_ex(resolved_path, 0);
+ }
+ return NULL;
}
}
- if (stream && stream->ops->seek && (stream->flags & PHP_STREAM_FLAG_NO_SEEK) == 0 && strchr(mode, 'a') && stream->position == 0) {
+ if (stream->ops->seek && (stream->flags & PHP_STREAM_FLAG_NO_SEEK) == 0 && strchr(mode, 'a') && stream->position == 0) {
zend_off_t newpos = 0;
/* if opened for append, we need to revise our idea of the initial file position */
@@ -2225,15 +2260,6 @@ 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, PHP_STREAM_EC(OpenFailed),
- "Failed to open stream");
- if (opened_path && *opened_path) {
- zend_string_release_ex(*opened_path, 0);
- *opened_path = NULL;
- }
- }
- php_stream_tidy_wrapper_name_error_log(wrapper_name);
pefree(wrapper_name, persistent);
if (resolved_path) {
zend_string_release_ex(resolved_path, 0);