From dde19a5007a4a8bec69257f2891fa02746a19b9d Mon Sep 17 00:00:00 2001 From: Peter Kokot Date: Sun, 28 Jun 2026 19:36:30 +0200 Subject: [PATCH 1/3] Sync #if/ifdef/defined (-Wundef) (#22474) The following macros are either defined (to 1) or undefined: * HAVE_CLOCK_GETTIME_NSEC_NP * HAVE_SYS_POLL_H * HAVE_SYS_WAIT_H * HAVE_TZSET * HAVE_WIFCONTINUED --- Zend/zend_hrtime.h | 2 +- ext/pcntl/php_pcntl.h | 2 +- ext/standard/proc_open.c | 8 ++++---- main/main.c | 2 +- main/network.c | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Zend/zend_hrtime.h b/Zend/zend_hrtime.h index 464c7e571d5b..6d802caacfe0 100644 --- a/Zend/zend_hrtime.h +++ b/Zend/zend_hrtime.h @@ -42,7 +42,7 @@ #elif defined(_WIN32) || defined(_WIN64) # undef ZEND_HRTIME_PLATFORM_WINDOWS # define ZEND_HRTIME_PLATFORM_WINDOWS 1 -#elif HAVE_CLOCK_GETTIME_NSEC_NP +#elif defined(HAVE_CLOCK_GETTIME_NSEC_NP) # undef ZEND_HRTIME_PLATFORM_APPLE_GETTIME_NSEC # define ZEND_HRTIME_PLATFORM_APPLE_GETTIME_NSEC 1 #elif defined(__APPLE__) diff --git a/ext/pcntl/php_pcntl.h b/ext/pcntl/php_pcntl.h index 17b86bca47d6..aaf1ea0ad473 100644 --- a/ext/pcntl/php_pcntl.h +++ b/ext/pcntl/php_pcntl.h @@ -17,7 +17,7 @@ #include "pcntl_decl.h" -#if defined(HAVE_DECL_WCONTINUED) && HAVE_DECL_WCONTINUED == 1 && defined(HAVE_WIFCONTINUED) && HAVE_WIFCONTINUED == 1 +#if defined(HAVE_DECL_WCONTINUED) && HAVE_DECL_WCONTINUED == 1 && defined(HAVE_WIFCONTINUED) #define HAVE_WCONTINUED 1 #endif diff --git a/ext/standard/proc_open.c b/ext/standard/proc_open.c index bd7a2e58854f..29744018a16d 100644 --- a/ext/standard/proc_open.c +++ b/ext/standard/proc_open.c @@ -266,7 +266,7 @@ static void proc_open_rsrc_dtor(zend_resource *rsrc) php_process_handle *proc = (php_process_handle*)rsrc->ptr; #ifdef PHP_WIN32 DWORD wstatus; -#elif HAVE_SYS_WAIT_H +#elif defined(HAVE_SYS_WAIT_H) int wstatus; int waitpid_options = 0; pid_t wait_pid; @@ -297,7 +297,7 @@ static void proc_open_rsrc_dtor(zend_resource *rsrc) } CloseHandle(proc->childHandle); -#elif HAVE_SYS_WAIT_H +#elif defined(HAVE_SYS_WAIT_H) if (!FG(pclose_wait)) { waitpid_options = WNOHANG; } @@ -389,7 +389,7 @@ PHP_FUNCTION(proc_get_status) php_process_handle *proc; #ifdef PHP_WIN32 DWORD wstatus; -#elif HAVE_SYS_WAIT_H +#elif defined(HAVE_SYS_WAIT_H) int wstatus; pid_t wait_pid; #endif @@ -418,7 +418,7 @@ PHP_FUNCTION(proc_get_status) * even if the child has already exited. This is because the result stays available * until the child handle is closed. Hence no caching is used on Windows. */ add_assoc_bool(return_value, "cached", false); -#elif HAVE_SYS_WAIT_H +#elif defined(HAVE_SYS_WAIT_H) wait_pid = waitpid_cached(proc, &wstatus, WNOHANG|WUNTRACED); if (wait_pid == proc->child) { diff --git a/main/main.c b/main/main.c index 6bda55ac8746..afb9fd410e82 100644 --- a/main/main.c +++ b/main/main.c @@ -2264,7 +2264,7 @@ zend_result php_module_startup(sapi_module_struct *sf, zend_module_entry *additi zend_reset_lc_ctype_locale(); zend_update_current_locale(); -#if HAVE_TZSET +#ifdef HAVE_TZSET tzset(); #endif diff --git a/main/network.c b/main/network.c index 90d1716b5582..84a755505b21 100644 --- a/main/network.c +++ b/main/network.c @@ -44,7 +44,7 @@ #endif #ifdef HAVE_POLL_H #include -#elif HAVE_SYS_POLL_H +#elif defined(HAVE_SYS_POLL_H) #include #endif From 51b934d445074fdae28a744d2b094297136137cd Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Sun, 28 Jun 2026 18:54:51 +0100 Subject: [PATCH 2/3] ext/openssl: convert stream errors to new stream error API (#22318) Convert the ext/openssl stream messages to the new stream error API so they honour the context error_mode/store like the other converted streams. All messages emitted while a stream error operation is open must go through the new API, otherwise mixing immediate php_error_docref() with buffered reporting reorders the output. This required emitting "Accept failed" via php_stream_warn() (adding StreamErrorCode::AcceptFailed) and threading a php_stream* through php_openssl_check_path_ex() (NULL for non-stream callers). Fingerprint changes: refactor php_openssl_x509_fingerprint_cmp() into an 'is equal' variant using zend_string; make php_openssl_x509_fingerprint_match() warn on all failure cases to avoid double warnings; thread a php_stream* into php_openssl_x509_fingerprint() so it reports through the operation, and demote its internal "Could not generate signature" failure from E_ERROR to a warning. Co-authored-by: Jakub Zelenka --- ext/openssl/openssl.c | 14 +- ext/openssl/openssl_backend_common.c | 20 +- ext/openssl/php_openssl.h | 17 +- ext/openssl/php_openssl_backend.h | 3 +- ext/openssl/tests/ServerClientTestCase.inc | 4 + ext/openssl/tests/bug68920.phpt | 4 - ext/openssl/xp_ssl.c | 226 ++++++++++-------- ext/standard/streamsfuncs.c | 2 +- ...stream_errors_exception_mode_terminal.phpt | 2 +- main/streams/stream_errors.stub.php | 2 + main/streams/stream_errors_arginfo.h | 6 +- main/streams/stream_errors_decl.h | 144 +++++------ 12 files changed, 246 insertions(+), 198 deletions(-) diff --git a/ext/openssl/openssl.c b/ext/openssl/openssl.c index 6b29471b2486..1e63eb1381f6 100644 --- a/ext/openssl/openssl.c +++ b/ext/openssl/openssl.c @@ -651,7 +651,8 @@ static void php_openssl_check_path_error(uint32_t arg_num, int type, const char /* openssl file path check extended */ bool php_openssl_check_path_ex( const char *file_path, size_t file_path_len, char *real_path, uint32_t arg_num, - bool contains_file_protocol, bool is_from_array, const char *option_name) + bool contains_file_protocol, bool is_from_array, const char *option_name, + php_stream *stream) { const char *fs_file_path; size_t fs_file_path_len; @@ -686,8 +687,13 @@ bool php_openssl_check_path_ex( if (arg_num == 0) { const char *option_title = option_name ? option_name : "unknown"; const char *option_label = is_from_array ? "array item" : "option"; - php_error_docref(NULL, E_WARNING, "Path for %s %s %s", - option_title, option_label, error_msg); + if (stream != NULL) { + php_stream_warn(stream, InvalidPath, "Path for %s %s %s", + option_title, option_label, error_msg); + } else { + php_error_docref(NULL, E_WARNING, "Path for %s %s %s", + option_title, option_label, error_msg); + } } else if (is_from_array && option_name != NULL) { php_openssl_check_path_error( arg_num, error_type, "option %s array item %s", option_name, error_msg); @@ -1294,7 +1300,7 @@ PHP_FUNCTION(openssl_x509_fingerprint) RETURN_FALSE; } - fingerprint = php_openssl_x509_fingerprint(cert, method, raw_output); + fingerprint = php_openssl_x509_fingerprint(cert, method, raw_output, NULL); if (fingerprint) { RETVAL_STR(fingerprint); } else { diff --git a/ext/openssl/openssl_backend_common.c b/ext/openssl/openssl_backend_common.c index ba9bccff98c0..8115a7c91b3a 100644 --- a/ext/openssl/openssl_backend_common.c +++ b/ext/openssl/openssl_backend_common.c @@ -307,7 +307,7 @@ int php_openssl_parse_config(struct php_x509_request * req, zval * optional_args /* read in the oids */ str = php_openssl_conf_get_string(req->req_config, NULL, "oid_file"); - if (str != NULL && php_openssl_check_path_ex(str, strlen(str), path, 0, false, false, "oid_file")) { + if (str != NULL && php_openssl_check_path_ex(str, strlen(str), path, 0, false, false, "oid_file", NULL)) { BIO *oid_bio = BIO_new_file(path, PHP_OPENSSL_BIO_MODE_R(PKCS7_BINARY)); if (oid_bio) { OBJ_create_objects(oid_bio); @@ -513,7 +513,7 @@ X509 *php_openssl_x509_from_str( BIO *in; if (ZSTR_LEN(cert_str) > 7 && memcmp(ZSTR_VAL(cert_str), "file://", sizeof("file://") - 1) == 0) { - if (!php_openssl_check_path_str_ex(cert_str, cert_path, arg_num, true, is_from_array, option_name)) { + if (!php_openssl_check_path_str_ex(cert_str, cert_path, arg_num, true, is_from_array, option_name, NULL)) { return NULL; } @@ -582,7 +582,7 @@ X509 *php_openssl_x509_from_zval( return cert; } -zend_string* php_openssl_x509_fingerprint(X509 *peer, const char *method, bool raw) +zend_string* php_openssl_x509_fingerprint(X509 *peer, const char *method, bool raw, php_stream *stream) { unsigned char md[EVP_MAX_MD_SIZE]; const EVP_MD *mdtype; @@ -590,12 +590,20 @@ zend_string* php_openssl_x509_fingerprint(X509 *peer, const char *method, bool r zend_string *ret; if (!(mdtype = php_openssl_get_evp_md_by_name(method))) { - php_error_docref(NULL, E_WARNING, "Unknown digest algorithm"); + if (stream != NULL) { + php_stream_warn(stream, Generic, "Unknown digest algorithm"); + } else { + php_error_docref(NULL, E_WARNING, "Unknown digest algorithm"); + } return NULL; } else if (!X509_digest(peer, mdtype, md, &n)) { php_openssl_release_evp_md(mdtype); php_openssl_store_errors(); - php_error_docref(NULL, E_ERROR, "Could not generate signature"); + if (stream != NULL) { + php_stream_warn(stream, EncodingFailed, "Could not generate signature"); + } else { + php_error_docref(NULL, E_WARNING, "Could not generate signature"); + } return NULL; } @@ -792,7 +800,7 @@ X509_STORE *php_openssl_setup_verify(zval *calist, uint32_t arg_num) return NULL; } - if (!php_openssl_check_path_str_ex(str, file_path, arg_num, false, true, NULL)) { + if (!php_openssl_check_path_str_ex(str, file_path, arg_num, false, true, NULL, NULL)) { zend_string_release(str); continue; } diff --git a/ext/openssl/php_openssl.h b/ext/openssl/php_openssl.h index 20a04bbcd1a0..b88a6c59e4e9 100644 --- a/ext/openssl/php_openssl.h +++ b/ext/openssl/php_openssl.h @@ -102,34 +102,39 @@ void php_openssl_store_errors(void); void php_openssl_errors_set_mark(void); void php_openssl_errors_restore_mark(void); -/* openssl file path extra */ +/* openssl file path extra + * When a non-NULL stream is passed and the path check fails for a stream context option + * (arg_num == 0), the warning is reported via the stream error API so it participates in + * any active stream error operation; otherwise it is emitted immediately. */ bool php_openssl_check_path_ex( const char *file_path, size_t file_path_len, char *real_path, uint32_t arg_num, - bool contains_file_protocol, bool is_from_array, const char *option_name); + bool contains_file_protocol, bool is_from_array, const char *option_name, + struct _php_stream *stream); /* openssl file path check */ static inline bool php_openssl_check_path( const char *file_path, size_t file_path_len, char *real_path, uint32_t arg_num) { return php_openssl_check_path_ex( - file_path, file_path_len, real_path, arg_num, false, false, NULL); + file_path, file_path_len, real_path, arg_num, false, false, NULL, NULL); } /* openssl file path extra check with zend string */ static inline bool php_openssl_check_path_str_ex( zend_string *file_path, char *real_path, uint32_t arg_num, - bool contains_file_protocol, bool is_from_array, const char *option_name) + bool contains_file_protocol, bool is_from_array, const char *option_name, + struct _php_stream *stream) { return php_openssl_check_path_ex( ZSTR_VAL(file_path), ZSTR_LEN(file_path), real_path, arg_num, contains_file_protocol, - is_from_array, option_name); + is_from_array, option_name, stream); } /* openssl file path check with zend string */ static inline bool php_openssl_check_path_str( zend_string *file_path, char *real_path, uint32_t arg_num) { - return php_openssl_check_path_str_ex(file_path, real_path, arg_num, true, false, NULL); + return php_openssl_check_path_str_ex(file_path, real_path, arg_num, true, false, NULL, NULL); } PHP_OPENSSL_API zend_long php_openssl_cipher_iv_length(const char *method); diff --git a/ext/openssl/php_openssl_backend.h b/ext/openssl/php_openssl_backend.h index 2d37e594ea57..bd12a5fe312f 100644 --- a/ext/openssl/php_openssl_backend.h +++ b/ext/openssl/php_openssl_backend.h @@ -262,7 +262,8 @@ X509 *php_openssl_x509_from_param( X509 *php_openssl_x509_from_zval( zval *val, bool *free_cert, uint32_t arg_num, bool is_from_array, const char *option_name); -zend_string* php_openssl_x509_fingerprint(X509 *peer, const char *method, bool raw); +zend_string* php_openssl_x509_fingerprint( + X509 *peer, const char *method, bool raw, struct _php_stream *stream); int openssl_x509v3_subjectAltName(BIO *bio, X509_EXTENSION *extension); diff --git a/ext/openssl/tests/ServerClientTestCase.inc b/ext/openssl/tests/ServerClientTestCase.inc index c5db41d48417..b7e866954fcf 100644 --- a/ext/openssl/tests/ServerClientTestCase.inc +++ b/ext/openssl/tests/ServerClientTestCase.inc @@ -129,6 +129,10 @@ class ServerClientTestCase private function cleanupWorkerProcess($worker) { fclose($this->workerStdIn[$worker]); + /* Drain stdout to EOF before closing it, so late worker writes (e.g. + * buffered error output) don't fail and abort the worker mid-output. */ + stream_set_blocking($this->workerStdOut[$worker], true); + stream_get_contents($this->workerStdOut[$worker]); fclose($this->workerStdOut[$worker]); proc_close($this->workerHandle[$worker]); } diff --git a/ext/openssl/tests/bug68920.phpt b/ext/openssl/tests/bug68920.phpt index 4abe12586b0b..a2d669e5b7d7 100644 --- a/ext/openssl/tests/bug68920.phpt +++ b/ext/openssl/tests/bug68920.phpt @@ -76,8 +76,6 @@ bool(false) Warning: stream_socket_client(): Invalid peer_fingerprint array; [algo => fingerprint] form required in %s on line %d -Warning: stream_socket_client(): peer_fingerprint match failure in %s on line %d - Warning: stream_socket_client(): Failed to enable crypto in %s on line %d Warning: stream_socket_client(): Unable to connect to %s (Unknown error) in %s on line %d @@ -85,8 +83,6 @@ bool(false) Warning: stream_socket_client(): Invalid peer_fingerprint array; [algo => fingerprint] form required in %s on line %d -Warning: stream_socket_client(): peer_fingerprint match failure in %s on line %d - Warning: stream_socket_client(): Failed to enable crypto in %s on line %d Warning: stream_socket_client(): Unable to connect to %s (Unknown error) in %s on line %d diff --git a/ext/openssl/xp_ssl.c b/ext/openssl/xp_ssl.c index a154aa4572f7..bc483df617b1 100644 --- a/ext/openssl/xp_ssl.c +++ b/ext/openssl/xp_ssl.c @@ -145,7 +145,8 @@ #endif extern php_stream* php_openssl_get_stream_from_ssl_handle(const SSL *ssl); -extern zend_string* php_openssl_x509_fingerprint(X509 *peer, const char *method, bool raw); +extern zend_string* php_openssl_x509_fingerprint( + X509 *peer, const char *method, bool raw, php_stream *stream); extern int php_openssl_get_ssl_stream_data_index(void); static struct timeval php_openssl_subtract_timeval(struct timeval a, struct timeval b); static int php_openssl_compare_timeval(struct timeval a, struct timeval b); @@ -281,16 +282,14 @@ static int php_openssl_handle_ssl_error(php_stream *stream, int nr_bytes, bool i if (ERR_peek_error() == 0) { if (nr_bytes == 0) { if (!php_openssl_is_http_stream_talking_to_iis(stream) && ERR_get_error() != 0) { - php_error_docref(NULL, E_WARNING, "SSL: fatal protocol error"); + php_stream_warn(stream, ProtocolError, "SSL: fatal protocol error"); } SSL_set_shutdown(sslsock->ssl_handle, SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN); stream->eof = 1; retry = false; } else { char *estr = php_socket_strerror(php_socket_errno(), NULL, 0); - - php_error_docref(NULL, E_WARNING, - "SSL: %s", estr); + php_stream_warn(stream, ProtocolError, "SSL: %s", estr); efree(estr); retry = false; @@ -305,7 +304,7 @@ static int php_openssl_handle_ssl_error(php_stream *stream, int nr_bytes, bool i switch (ERR_GET_REASON(ecode)) { case SSL_R_NO_SHARED_CIPHER: - php_error_docref(NULL, E_WARNING, + php_stream_warn(stream, ProtocolError, "SSL_R_NO_SHARED_CIPHER: no suitable shared cipher could be used. " "This could be because the server is missing an SSL certificate " "(local_cert context option)"); @@ -324,7 +323,7 @@ static int php_openssl_handle_ssl_error(php_stream *stream, int nr_bytes, bool i smart_str_0(&ebuf); - php_error_docref(NULL, E_WARNING, + php_stream_warn(stream, ProtocolError, "SSL operation failed with code %d. %s%s", err, ebuf.s ? "OpenSSL Error messages:\n" : "", @@ -379,21 +378,19 @@ static int verify_callback(int preverify_ok, X509_STORE_CTX *ctx) /* {{{ */ } /* }}} */ -static int php_openssl_x509_fingerprint_cmp(X509 *peer, const char *method, const char *expected) +static bool php_openssl_x509_fingerprint_is_equal(php_stream *stream, X509 *peer, const char *method, const zend_string *expected) { - zend_string *fingerprint; - int result = -1; - - fingerprint = php_openssl_x509_fingerprint(peer, method, false); + bool is_equal = false; + zend_string *fingerprint = php_openssl_x509_fingerprint(peer, method, false, stream); if (fingerprint) { - result = strcasecmp(expected, ZSTR_VAL(fingerprint)); - zend_string_release_ex(fingerprint, 0); + is_equal = zend_string_equals_ci(fingerprint, expected); + zend_string_release_ex(fingerprint, false); } - return result; + return is_equal; } -static bool php_openssl_x509_fingerprint_match(X509 *peer, zval *val) +static bool php_openssl_x509_fingerprint_match(php_stream *stream, X509 *peer, const zval *val) { if (Z_TYPE_P(val) == IS_STRING) { const char *method = NULL; @@ -408,29 +405,41 @@ static bool php_openssl_x509_fingerprint_match(X509 *peer, zval *val) break; } - return method && php_openssl_x509_fingerprint_cmp(peer, method, Z_STRVAL_P(val)) == 0; + if (UNEXPECTED(method == NULL)) { + php_stream_warn(stream, AuthFailed, "peer_fingerprint length doesn't match a md5 or sha1 hash"); + return false; + } + if (!php_openssl_x509_fingerprint_is_equal(stream, peer, method, Z_STR_P(val))) { + php_stream_warn(stream, AuthFailed, "peer_fingerprint match failure"); + return false; + } + return true; } else if (Z_TYPE_P(val) == IS_ARRAY) { zval *current; zend_string *key; if (!zend_hash_num_elements(Z_ARRVAL_P(val))) { - php_error_docref(NULL, E_WARNING, "Invalid peer_fingerprint array; [algo => fingerprint] form required"); + // TODO: Should this be a ValueError (also must not be empty error)? + php_stream_warn(stream, Generic, "Invalid peer_fingerprint array; [algo => fingerprint] form required"); return false; } ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(val), key, current) { if (key == NULL || Z_TYPE_P(current) != IS_STRING) { - php_error_docref(NULL, E_WARNING, "Invalid peer_fingerprint array; [algo => fingerprint] form required"); + // TODO: Should this be a ValueError? + php_stream_warn(stream, Generic, "Invalid peer_fingerprint array; [algo => fingerprint] form required"); return false; } - if (php_openssl_x509_fingerprint_cmp(peer, ZSTR_VAL(key), Z_STRVAL_P(current)) != 0) { + if (!php_openssl_x509_fingerprint_is_equal(stream, peer, ZSTR_VAL(key), Z_STR_P(current))) { + php_stream_warn(stream, AuthFailed, "peer_fingerprint match failure"); return false; } } ZEND_HASH_FOREACH_END(); return true; } else { - php_error_docref(NULL, E_WARNING, + // TODO: Should this be a TypeError? + php_stream_warn(stream, Generic, "Invalid peer_fingerprint value; fingerprint string or array of the form [algo => fingerprint] required"); } @@ -555,7 +564,7 @@ static bool php_openssl_matches_san_list(X509 *peer, const char *subject_name) / } /* }}} */ -static bool php_openssl_matches_common_name(X509 *peer, const char *subject_name) /* {{{ */ +static bool php_openssl_matches_common_name(php_stream *stream, const X509 *peer, const char *subject_name) /* {{{ */ { char buf[1024]; X509_NAME *cert_name; @@ -566,13 +575,13 @@ static bool php_openssl_matches_common_name(X509 *peer, const char *subject_name cert_name_len = X509_NAME_get_text_by_NID(cert_name, NID_commonName, buf, sizeof(buf)); if (cert_name_len == -1) { - php_error_docref(NULL, E_WARNING, "Unable to locate peer certificate CN"); + php_stream_warn(stream, NetworkRecvFailed, "Unable to locate peer certificate CN"); } else if ((size_t)cert_name_len != strlen(buf)) { - php_error_docref(NULL, E_WARNING, "Peer certificate CN=`%.*s' is malformed", cert_name_len, buf); + php_stream_warn(stream, AuthFailed, "Peer certificate CN=`%.*s' is malformed", cert_name_len, buf); } else if (php_openssl_matches_wildcard_name(subject_name, buf)) { is_match = true; } else { - php_error_docref(NULL, E_WARNING, + php_stream_warn(stream, AuthFailed, "Peer certificate CN=`%.*s' did not match expected CN=`%s'", cert_name_len, buf, subject_name); } @@ -605,7 +614,7 @@ static zend_result php_openssl_apply_peer_verification_policy(SSL *ssl, X509 *pe peer_fingerprint = val; if ((must_verify_peer || must_verify_peer_name || must_verify_fingerprint) && peer == NULL) { - php_error_docref(NULL, E_WARNING, "Could not get peer certificate"); + php_stream_warn(stream, NetworkRecvFailed, "Could not get peer certificate"); return FAILURE; } @@ -624,8 +633,7 @@ static zend_result php_openssl_apply_peer_verification_policy(SSL *ssl, X509 *pe /* not allowed, so fall through */ ZEND_FALLTHROUGH; default: - php_error_docref(NULL, E_WARNING, - "Could not verify peer: code:%d %s", + php_stream_warn(stream, AuthFailed, "Could not verify peer: code:%d %s", err, X509_verify_cert_error_string(err) ); @@ -636,14 +644,11 @@ static zend_result php_openssl_apply_peer_verification_policy(SSL *ssl, X509 *pe /* If a peer_fingerprint match is required this trumps peer and peer_name verification */ if (must_verify_fingerprint) { if (Z_TYPE_P(peer_fingerprint) == IS_STRING || Z_TYPE_P(peer_fingerprint) == IS_ARRAY) { - if (!php_openssl_x509_fingerprint_match(peer, peer_fingerprint)) { - php_error_docref(NULL, E_WARNING, - "peer_fingerprint match failure" - ); + if (!php_openssl_x509_fingerprint_match(stream, peer, peer_fingerprint)) { return FAILURE; } } else { - php_error_docref(NULL, E_WARNING, + php_stream_warn(stream, AuthFailed, "Expected peer fingerprint must be a string or an array" ); return FAILURE; @@ -662,7 +667,7 @@ static zend_result php_openssl_apply_peer_verification_policy(SSL *ssl, X509 *pe if (peer_name) { if (php_openssl_matches_san_list(peer, peer_name)) { return SUCCESS; - } else if (php_openssl_matches_common_name(peer, peer_name)) { + } else if (php_openssl_matches_common_name(stream, peer, peer_name)) { return SUCCESS; } else { return FAILURE; @@ -725,7 +730,8 @@ static int php_openssl_win_cert_verify_callback(X509_STORE_CTX *x509_store_ctx, err_code = e; } - php_error_docref(NULL, E_WARNING, "Error encoding X509 certificate: %lu: %s", err_code, ERR_error_string(err_code, err_buf)); + php_stream_warn(stream, EncodingFailed, + "Error encoding X509 certificate: %lu: %s", err_code, ERR_error_string(err_code, err_buf)); RETURN_CERT_VERIFY_FAILURE(SSL_R_CERTIFICATE_VERIFY_FAILED); } @@ -734,7 +740,7 @@ static int php_openssl_win_cert_verify_callback(X509_STORE_CTX *x509_store_ctx, if (cert_ctx == NULL) { char *err = php_win_err(); - php_error_docref(NULL, E_WARNING, "Error creating certificate context: %s", err); + php_stream_warn(stream, CreateFailed, "Error creating certificate context: %s", err); php_win_err_free(err); RETURN_CERT_VERIFY_FAILURE(SSL_R_CERTIFICATE_VERIFY_FAILED); } @@ -758,7 +764,7 @@ static int php_openssl_win_cert_verify_callback(X509_STORE_CTX *x509_store_ctx, if (!CertGetCertificateChain(NULL, cert_ctx, NULL, NULL, &chain_params, chain_flags, NULL, &cert_chain_ctx)) { char *err = php_win_err(); - php_error_docref(NULL, E_WARNING, "Error getting certificate chain: %s", err); + php_stream_warn(stream, NetworkRecvFailed, "Error getting certificate chain: %s", err); php_win_err_free(err); CertFreeCertificateContext(cert_ctx); RETURN_CERT_VERIFY_FAILURE(SSL_R_CERTIFICATE_VERIFY_FAILED); @@ -801,7 +807,7 @@ static int php_openssl_win_cert_verify_callback(X509_STORE_CTX *x509_store_ctx, if (!verify_result) { char *err = php_win_err(); - php_error_docref(NULL, E_WARNING, "Error verifying certificate chain policy: %s", err); + php_stream_warn(stream, AuthFailed, "Error verifying certificate chain policy: %s", err); php_win_err_free(err); RETURN_CERT_VERIFY_FAILURE(SSL_R_CERTIFICATE_VERIFY_FAILED); } @@ -836,11 +842,12 @@ static long php_openssl_load_stream_cafile(X509_STORE *cert_store, const char *c stream = php_stream_open_wrapper(cafile, "rb", 0, NULL); if (stream == NULL) { + // TODO: no stream and no wrapper, cannot use php_stream_warn(stream, ReadFailed, ...) nor php_stream_wrapper_log_error() php_error(E_WARNING, "failed loading cafile stream: `%s'", cafile); return 0; } else if (stream->wrapper->is_url) { + php_stream_warn(stream, PermissionDenied, "remote cafile streams are disabled for security purposes"); php_stream_close(stream); - php_error(E_WARNING, "remote cafile streams are disabled for security purposes"); return 0; } @@ -898,7 +905,7 @@ static long php_openssl_load_stream_cafile(X509_STORE *cert_store, const char *c } if (certs_added == 0) { - php_error(E_WARNING, "no valid certs found cafile stream: `%s'", cafile); + php_stream_warn(stream, DecodingFailed, "no valid certs found cafile stream: `%s'", cafile); } return certs_added; @@ -924,7 +931,7 @@ static zend_result php_openssl_enable_peer_verification(SSL_CTX *ctx, php_stream if (cert_names != NULL) { SSL_CTX_set_client_CA_list(ctx, cert_names); } else { - php_error(E_WARNING, "SSL: failed loading CA names from cafile"); + php_stream_warn(stream, InvalidFormat, "SSL: failed loading CA names from cafile"); return FAILURE; } } @@ -946,7 +953,7 @@ static zend_result php_openssl_enable_peer_verification(SSL_CTX *ctx, php_stream SSL_CTX_set_cert_verify_callback(ctx, php_openssl_win_cert_verify_callback, (void *)stream); #else if (sslsock->is_client && !SSL_CTX_set_default_verify_paths(ctx)) { - php_error_docref(NULL, E_WARNING, + php_stream_warn(stream, ProtocolError, "Unable to set default verify locations and no CA settings specified"); return FAILURE; } @@ -980,13 +987,13 @@ static zend_result php_openssl_set_local_cert(SSL_CTX *ctx, php_stream *stream) if (!php_openssl_check_path_ex( certfile, certfile_len, resolved_path_buff, 0, false, false, - "local_cert in ssl stream context")) { - php_error_docref(NULL, E_WARNING, "Unable to get real path of certificate file `%s'", certfile); + "local_cert in ssl stream context", stream)) { + php_stream_warn(stream, NotFound, "Unable to get real path of certificate file `%s'", certfile); return FAILURE; } /* a certificate to use for authentication */ if (SSL_CTX_use_certificate_chain_file(ctx, resolved_path_buff) != 1) { - php_error_docref(NULL, E_WARNING, + php_stream_warn(stream, WriteFailed, "Unable to set local cert chain file `%s'; Check that your cafile/capath " "settings include details of your certificate and its issuer", certfile); @@ -996,16 +1003,16 @@ static zend_result php_openssl_set_local_cert(SSL_CTX *ctx, php_stream *stream) GET_VER_OPT_STRINGL("local_pk", private_key, private_key_len); if (private_key && !php_openssl_check_path_ex( private_key, private_key_len, resolved_path_buff, 0, false, false, - "local_pk in ssl stream context")) { - php_error_docref(NULL, E_WARNING, "Unable to get real path of private key file `%s'", private_key); + "local_pk in ssl stream context", stream)) { + php_stream_warn(stream, NotFound, "Unable to get real path of private key file `%s'", private_key); return FAILURE; } if (SSL_CTX_use_PrivateKey_file(ctx, resolved_path_buff, SSL_FILETYPE_PEM) != 1) { - php_error_docref(NULL, E_WARNING, "Unable to set private key file `%s'", resolved_path_buff); + php_stream_warn(stream, WriteFailed, "Unable to set private key file `%s'", resolved_path_buff); return FAILURE; } if (!SSL_CTX_check_private_key(ctx)) { - php_error_docref(NULL, E_WARNING, "Private key does not match certificate!"); + php_stream_warn(stream, PermissionDenied, "Private key does not match certificate!"); } } @@ -1140,7 +1147,7 @@ static void php_openssl_limit_handshake_reneg(const SSL *ssl) /* {{{ */ /* Closing the stream inside this callback would segfault! */ stream->flags |= PHP_STREAM_FLAG_NO_FCLOSE; if (FAILURE == call_user_function(NULL, NULL, val, &retval, 1, ¶m)) { - php_error(E_WARNING, "SSL: failed invoking reneg limit notification callback"); + php_stream_warn(stream, UserspaceCallFailed, "SSL: failed invoking reneg limit notification callback"); } stream->flags ^= PHP_STREAM_FLAG_NO_FCLOSE; @@ -1151,7 +1158,7 @@ static void php_openssl_limit_handshake_reneg(const SSL *ssl) /* {{{ */ zval_ptr_dtor(&retval); } else { - php_error_docref(NULL, E_WARNING, + php_stream_warn(stream, ProtocolError, "SSL: client-initiated handshake rate limit exceeded by peer"); } } @@ -1224,7 +1231,7 @@ static zend_result php_openssl_set_server_dh_param(php_stream * stream, SSL_CTX BIO *bio = BIO_new_file(Z_STRVAL_P(zdhpath), PHP_OPENSSL_BIO_MODE_R(PKCS7_BINARY)); if (bio == NULL) { - php_error_docref(NULL, E_WARNING, "Invalid dh_param"); + php_stream_warn(stream, NotFound, "Invalid dh_param"); return FAILURE; } @@ -1233,12 +1240,12 @@ static zend_result php_openssl_set_server_dh_param(php_stream * stream, SSL_CTX BIO_free(bio); if (pkey == NULL) { - php_error_docref(NULL, E_WARNING, "Failed reading DH params"); + php_stream_warn(stream, ReadFailed, "Failed reading DH params"); return FAILURE; } if (SSL_CTX_set0_tmp_dh_pkey(ctx, pkey) == 0) { - php_error_docref(NULL, E_WARNING, "Failed assigning DH params"); + php_stream_warn(stream, WriteFailed, "Failed assigning DH params"); EVP_PKEY_free(pkey); return FAILURE; } @@ -1247,12 +1254,12 @@ static zend_result php_openssl_set_server_dh_param(php_stream * stream, SSL_CTX BIO_free(bio); if (dh == NULL) { - php_error_docref(NULL, E_WARNING, "Failed reading DH params"); + php_stream_warn(stream, ReadFailed, "Failed reading DH params"); return FAILURE; } if (SSL_CTX_set_tmp_dh(ctx, dh) == 0) { - php_error_docref(NULL, E_WARNING, "Failed assigning DH params"); + php_stream_warn(stream, WriteFailed, "Failed assigning DH params"); DH_free(dh); return FAILURE; } @@ -1271,7 +1278,8 @@ static zend_result php_openssl_set_server_specific_opts(php_stream *stream, SSL_ /* We now use php_openssl_tmp_rsa_cb to generate a key of appropriate size whenever necessary */ if (php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "ssl", "rsa_key_size") != NULL) { - php_error_docref(NULL, E_WARNING, "rsa_key_size context option has been removed"); + // TODO: Should this be E_DEPRECATED instead? + php_stream_warn(stream, Generic, "rsa_key_size context option has been removed"); } if (php_openssl_set_server_dh_param(stream, ctx) == FAILURE) { @@ -1326,18 +1334,18 @@ static int php_openssl_server_sni_callback(SSL *ssl_handle, int *al, void *arg) } /* }}} */ -static SSL_CTX *php_openssl_create_sni_server_ctx(char *cert_path, char *key_path) /* {{{ */ +static SSL_CTX *php_openssl_create_sni_server_ctx(php_stream *stream, char *cert_path, char *key_path) /* {{{ */ { /* The hello method is not inherited by SSL structs when assigning a new context * inside the SNI callback, so the just use SSLv23 */ SSL_CTX *ctx = SSL_CTX_new(SSLv23_server_method()); if (!ctx) { - php_error_docref(NULL, E_WARNING, "Failed to create the SSL context"); + php_stream_warn(stream, CreateFailed, "Failed to create the SSL context"); return NULL; } if (SSL_CTX_use_certificate_chain_file(ctx, cert_path) != 1) { - php_error_docref(NULL, E_WARNING, + php_stream_warn(stream, ReadFailed, "Failed setting local cert chain file `%s'; " \ "check that your cafile/capath settings include " \ "details of your certificate and its issuer", @@ -1346,7 +1354,7 @@ static SSL_CTX *php_openssl_create_sni_server_ctx(char *cert_path, char *key_pat SSL_CTX_free(ctx); return NULL; } else if (SSL_CTX_use_PrivateKey_file(ctx, key_path, SSL_FILETYPE_PEM) != 1) { - php_error_docref(NULL, E_WARNING, + php_stream_warn(stream, ReadFailed, "Failed setting private key from file `%s'", key_path ); @@ -1380,7 +1388,8 @@ static zend_result php_openssl_enable_server_sni( } if (Z_TYPE_P(val) != IS_ARRAY) { - php_error_docref(NULL, E_WARNING, + // TODO: should this be a TypeError? + php_stream_warn(stream, Generic, "SNI_server_certs requires an array mapping host names to cert paths" ); return FAILURE; @@ -1388,7 +1397,8 @@ static zend_result php_openssl_enable_server_sni( sslsock->sni_cert_count = zend_hash_num_elements(Z_ARRVAL_P(val)); if (sslsock->sni_cert_count == 0) { - php_error_docref(NULL, E_WARNING, + // TODO: should this be a ValueError? + php_stream_warn(stream, Generic, "SNI_server_certs host cert array must not be empty" ); return FAILURE; @@ -1403,7 +1413,8 @@ static zend_result php_openssl_enable_server_sni( (void) key_index; if (!key) { - php_error_docref(NULL, E_WARNING, + // TODO: should this be a ValueError? + php_stream_warn(stream, Generic, "SNI_server_certs array requires string host name keys" ); return FAILURE; @@ -1418,7 +1429,8 @@ static zend_result php_openssl_enable_server_sni( local_cert = zend_hash_str_find(Z_ARRVAL_P(current), "local_cert", sizeof("local_cert")-1); if (local_cert == NULL) { - php_error_docref(NULL, E_WARNING, + // TODO: should this be a ValueError? + php_stream_warn(stream, Generic, "local_cert not present in the array" ); return FAILURE; @@ -1430,8 +1442,8 @@ static zend_result php_openssl_enable_server_sni( } if (!php_openssl_check_path_str_ex( local_cert_str, resolved_cert_path_buff, 0, false, false, - "SNI_server_certs local_cert in ssl stream context")) { - php_error_docref(NULL, E_WARNING, + "SNI_server_certs local_cert in ssl stream context", stream)) { + php_stream_warn(stream, OpenFailed, "Failed setting local cert chain file `%s'; could not open file", ZSTR_VAL(local_cert_str) ); @@ -1442,7 +1454,8 @@ static zend_result php_openssl_enable_server_sni( local_pk = zend_hash_str_find(Z_ARRVAL_P(current), "local_pk", sizeof("local_pk")-1); if (local_pk == NULL) { - php_error_docref(NULL, E_WARNING, + // TODO: should this be a ValueError? + php_stream_warn(stream, Generic, "local_pk not present in the array" ); return FAILURE; @@ -1454,8 +1467,8 @@ static zend_result php_openssl_enable_server_sni( } if (!php_openssl_check_path_str_ex( local_pk_str, resolved_pk_path_buff, 0, false, false, - "SNI_server_certs local_pk in ssl stream context")) { - php_error_docref(NULL, E_WARNING, + "SNI_server_certs local_pk in ssl stream context", stream)) { + php_stream_warn(stream, OpenFailed, "Failed setting local private key file `%s'; could not open file", ZSTR_VAL(local_pk_str) ); @@ -1464,18 +1477,19 @@ static zend_result php_openssl_enable_server_sni( } zend_string_release(local_pk_str); - ctx = php_openssl_create_sni_server_ctx(resolved_cert_path_buff, resolved_pk_path_buff); + ctx = php_openssl_create_sni_server_ctx(stream, resolved_cert_path_buff, resolved_pk_path_buff); } else if (Z_TYPE_P(current) == IS_STRING) { - if (php_openssl_check_path_str_ex(Z_STR_P(current), resolved_path_buff, 0, false, false, "SNI_server_certs in ssl stream context")) { - ctx = php_openssl_create_sni_server_ctx(resolved_path_buff, resolved_path_buff); + if (php_openssl_check_path_str_ex(Z_STR_P(current), resolved_path_buff, 0, false, false, "SNI_server_certs in ssl stream context", stream)) { + ctx = php_openssl_create_sni_server_ctx(stream, resolved_path_buff, resolved_path_buff); } else { - php_error_docref(NULL, E_WARNING, + php_stream_warn(stream, NotFound, "Failed setting local cert chain file `%s'; file not found", Z_STRVAL_P(current) ); } } else { - php_error_docref(NULL, E_WARNING, "SNI_server_certs options values must be of type array|string"); + // TODO: should this be a TypeError? + php_stream_warn(stream, Generic, "SNI_server_certs options values must be of type array|string"); } if (ctx == NULL) { @@ -1902,12 +1916,13 @@ static int php_openssl_psk_find_session_cb(SSL *ssl, const unsigned char *identi /* PSK setup */ static zend_result php_openssl_validate_and_allocate_psk_callback( + php_stream *stream, php_openssl_netstream_data_t *sslsock, const zval *callable, bool is_client, bool is_persistent) { const char *callback_name = is_client ? "psk_client_cb" : "psk_server_cb"; if (is_persistent) { - php_error_docref(NULL, E_WARNING, + php_stream_warn(stream, PersistentNotSupported, "%s is not supported for persistent streams", callback_name); return FAILURE; } @@ -1950,7 +1965,7 @@ static zend_result php_openssl_setup_client_psk(php_stream *stream, } if (FAILURE == php_openssl_validate_and_allocate_psk_callback( - sslsock, val, true, php_stream_is_persistent(stream))) { + stream, sslsock, val, true, php_stream_is_persistent(stream))) { return FAILURE; } @@ -1972,7 +1987,7 @@ static zend_result php_openssl_setup_server_psk(php_stream *stream, } if (FAILURE == php_openssl_validate_and_allocate_psk_callback( - sslsock, val, false, php_stream_is_persistent(stream))) { + stream, sslsock, val, false, php_stream_is_persistent(stream))) { return FAILURE; } @@ -2103,6 +2118,7 @@ enum php_openssl_session_callback_type { * Validate callable and allocate callback structure if needed. */ static zend_result php_openssl_validate_and_allocate_session_callback( + php_stream *stream, php_openssl_netstream_data_t *sslsock, const zval *callable, enum php_openssl_session_callback_type cb_type, bool is_persistent) { @@ -2123,7 +2139,7 @@ static zend_result php_openssl_validate_and_allocate_session_callback( /* Callbacks not supported for persistent streams */ if (is_persistent) { - php_error_docref(NULL, E_WARNING, + php_stream_warn(stream, PersistentNotSupported, "%s is not supported for persistent streams", callback_name); return FAILURE; } @@ -2184,7 +2200,7 @@ static zend_result php_openssl_setup_client_session(php_stream *stream, if (GET_VER_OPT("session_new_cb")) { if (FAILURE == php_openssl_validate_and_allocate_session_callback( - sslsock, val, PHP_OPENSSL_NEW_CB, is_persistent)) { + stream, sslsock, val, PHP_OPENSSL_NEW_CB, is_persistent)) { return FAILURE; } @@ -2231,7 +2247,7 @@ static zend_result php_openssl_setup_server_session(php_stream *stream, /* Check for session_get_cb first (determines cache mode) */ if (GET_VER_OPT("session_get_cb")) { if (FAILURE == php_openssl_validate_and_allocate_session_callback( - sslsock, val, PHP_OPENSSL_GET_CB, is_persistent)) { + stream, sslsock, val, PHP_OPENSSL_GET_CB, is_persistent)) { return FAILURE; } has_get_cb = true; @@ -2250,7 +2266,7 @@ static zend_result php_openssl_setup_server_session(php_stream *stream, /* Check for session_new_cb */ if (GET_VER_OPT("session_new_cb")) { if (FAILURE == php_openssl_validate_and_allocate_session_callback( - sslsock, val, PHP_OPENSSL_NEW_CB, is_persistent)) { + stream, sslsock, val, PHP_OPENSSL_NEW_CB, is_persistent)) { return FAILURE; } has_new_cb = true; @@ -2271,7 +2287,7 @@ static zend_result php_openssl_setup_server_session(php_stream *stream, /* Check for session_remove_cb (optional) */ if (GET_VER_OPT("session_remove_cb")) { if (FAILURE == php_openssl_validate_and_allocate_session_callback( - sslsock, val, PHP_OPENSSL_REMOVE_CB, is_persistent)) { + stream, sslsock, val, PHP_OPENSSL_REMOVE_CB, is_persistent)) { return FAILURE; } @@ -2356,7 +2372,8 @@ static zend_result php_openssl_apply_client_session_data(php_stream *stream, if (php_openssl_is_session_ce(val)) { session = php_openssl_session_from_zval(val); if (!session) { - php_error_docref(NULL, E_WARNING, + // TODO: Should this be a TypeError? + php_stream_warn(stream, Generic, "Invalid OpenSSLSession object, falling back to full handshake"); return FAILURE; } @@ -2369,7 +2386,7 @@ static zend_result php_openssl_apply_client_session_data(php_stream *stream, if (session) { if (SSL_set_session(sslsock->ssl_handle, session) != 1) { - php_error_docref(NULL, E_WARNING, + php_stream_warn(stream, ResumptionFailed, "Failed to set session for resumption, falling back to full handshake"); if (needs_free) { SSL_SESSION_free(session); @@ -2396,7 +2413,7 @@ static zend_result php_openssl_create_server_ctx(php_stream *stream, sslsock->ctx = SSL_CTX_new(method); if (sslsock->ctx == NULL) { - php_error_docref(NULL, E_WARNING, "SSL context creation failure"); + php_stream_warn(stream, CreateFailed, "SSL context creation failure"); return FAILURE; } @@ -2462,7 +2479,8 @@ static zend_result php_openssl_create_server_ctx(php_stream *stream, if (GET_VER_OPT("security_level")) { zend_long lval = zval_get_long(val); if (lval < 0 || lval > 5) { - php_error_docref(NULL, E_WARNING, "Security level must be between 0 and 5"); + // TODO: Should this be a ValueError? + php_stream_warn(stream, Generic, "Security level must be between 0 and 5"); } #ifdef HAVE_SEC_LEVEL SSL_CTX_set_security_level(sslsock->ctx, lval); @@ -2478,7 +2496,7 @@ static zend_result php_openssl_create_server_ctx(php_stream *stream, unsigned char *alpn = php_openssl_alpn_protos_parse(&alpn_len, alpn_protocols); if (alpn == NULL) { - php_error_docref(NULL, E_WARNING, "Failed parsing comma-separated TLS ALPN protocol string"); + php_stream_warn(stream, DecodingFailed, "Failed parsing comma-separated TLS ALPN protocol string"); SSL_CTX_free(sslsock->ctx); sslsock->ctx = NULL; return FAILURE; @@ -2494,7 +2512,7 @@ static zend_result php_openssl_create_server_ctx(php_stream *stream, efree(alpn); } #else - php_error_docref(NULL, E_WARNING, + php_stream_warn(stream, ProtocolUnsupported, "alpn_protocols support is not compiled into the OpenSSL library against which PHP is linked"); #endif } @@ -2544,7 +2562,7 @@ static zend_result php_openssl_setup_crypto(php_stream *stream, { if (sslsock->ssl_handle) { if (sslsock->s.is_blocked) { - php_error_docref(NULL, E_WARNING, "SSL/TLS already set-up for this stream"); + php_stream_warn(stream, Generic, "SSL/TLS already set-up for this stream"); return FAILURE; } else { return SUCCESS; @@ -2563,11 +2581,11 @@ static zend_result php_openssl_setup_crypto(php_stream *stream, php_openssl_netstream_data_t *parent_sslsock; if (cparam->inputs.session->ops != &php_openssl_socket_ops) { - php_error_docref(NULL, E_WARNING, "Supplied session stream must be an SSL enabled stream"); + php_stream_warn(stream, SslNotSupported, "Supplied session stream must be an SSL enabled stream"); } else if ((parent_sslsock = cparam->inputs.session->abstract)->ctx == NULL) { - php_error_docref(NULL, E_WARNING, "Supplied SSL session stream is not set up"); + php_stream_warn(stream, SslNotSupported, "Supplied SSL session stream is not set up"); } else if (sslsock->is_client && parent_sslsock->ssl_handle == NULL) { - php_error_docref(NULL, E_WARNING, "Supplied SSL session stream is not initialized"); + php_stream_warn(stream, SslNotSupported, "Supplied SSL session stream is not initialized"); } else { SSL_CTX_up_ref(parent_sslsock->ctx); sslsock->ctx = parent_sslsock->ctx; @@ -2582,7 +2600,7 @@ static zend_result php_openssl_setup_crypto(php_stream *stream, sslsock->ssl_handle = SSL_new(sslsock->ctx); if (!sslsock->ssl_handle) { - php_error_docref(NULL, E_WARNING, "SSL handle creation failure"); + php_stream_warn(stream, CreateFailed, "SSL handle creation failure"); SSL_CTX_free(sslsock->ctx); sslsock->ctx = NULL; return FAILURE; @@ -2598,7 +2616,7 @@ static zend_result php_openssl_setup_crypto(php_stream *stream, if (SSL_copy_session_id(sslsock->ssl_handle, parent_sslsock->ssl_handle)) { SSL_CTX_set_session_cache_mode(sslsock->ctx, SSL_SESS_CACHE_CLIENT); } else { - php_error_docref(NULL, E_WARNING, "SSL session copying failed creation failure"); + php_stream_warn(stream, CreateFailed, "SSL session copying failed creation failure"); } } @@ -2614,7 +2632,7 @@ static zend_result php_openssl_setup_crypto(php_stream *stream, if (sslsock->ssl_handle == NULL || !SSL_set_ex_data(sslsock->ssl_handle, php_openssl_get_ssl_stream_data_index(), stream)) { - php_error_docref(NULL, E_WARNING, "SSL handle creation failure"); + php_stream_warn(stream, CreateFailed, "SSL handle creation failure"); SSL_CTX_free(sslsock->ctx); sslsock->ctx = NULL; #ifdef HAVE_TLS_ALPN @@ -2764,7 +2782,7 @@ static int php_openssl_enable_crypto(php_stream *stream, elapsed_time = php_openssl_subtract_timeval(cur_time, start_time); if (php_openssl_compare_timeval( elapsed_time, *timeout) > 0) { - php_error_docref(NULL, E_WARNING, "SSL: Handshake timed out"); + php_stream_warn(stream, TimeOut, "SSL: Handshake timed out"); return -1; } } @@ -3220,7 +3238,7 @@ static inline int php_openssl_tcp_sockop_accept(php_stream *stream, php_openssl_ if (php_stream_xport_crypto_setup(xparam->outputs.client, clisockdata->method, sock->ctx ? stream : NULL) < 0 || php_stream_xport_crypto_enable( xparam->outputs.client, 1) < 0) { - php_error_docref(NULL, E_WARNING, "Failed to enable crypto"); + php_stream_warn(stream, ProtocolError, "Failed to enable crypto"); php_stream_close(xparam->outputs.client); xparam->outputs.client = NULL; @@ -3490,7 +3508,7 @@ static int php_openssl_sockop_set_option(php_stream *stream, int option, int val if (php_stream_xport_crypto_setup(stream, sslsock->method, session_stream) < 0 || php_stream_xport_crypto_enable(stream, 1) < 0) { - php_error_docref(NULL, E_WARNING, "Failed to enable crypto"); + php_stream_warn(stream, ProtocolError, "Failed to enable crypto"); xparam->outputs.returncode = -1; } } @@ -3686,7 +3704,7 @@ php_stream *php_openssl_ssl_socket_factory(const char *proto, size_t protolen, sslsock->enable_on_connect = 1; sslsock->method = php_openssl_get_crypto_method(context, STREAM_CRYPTO_METHOD_TLS_ANY_CLIENT); } else if (strncmp(proto, "sslv2", protolen) == 0) { - php_error_docref(NULL, E_WARNING, "SSLv2 unavailable in this PHP version"); + php_stream_warn(stream, ProtocolUnsupported, "SSLv2 unavailable in this PHP version"); php_stream_close(stream); return NULL; } else if (strncmp(proto, "sslv3", protolen) == 0) { @@ -3694,7 +3712,7 @@ php_stream *php_openssl_ssl_socket_factory(const char *proto, size_t protolen, sslsock->enable_on_connect = 1; sslsock->method = STREAM_CRYPTO_METHOD_SSLv3_CLIENT; #else - php_error_docref(NULL, E_WARNING, + php_stream_warn(stream, ProtocolUnsupported, "SSLv3 support is not compiled into the OpenSSL library against which PHP is linked"); php_stream_close(stream); return NULL; @@ -3710,7 +3728,7 @@ php_stream *php_openssl_ssl_socket_factory(const char *proto, size_t protolen, sslsock->enable_on_connect = 1; sslsock->method = STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT; #else - php_error_docref(NULL, E_WARNING, + php_stream_warn(stream, ProtocolUnsupported, "TLSv1.1 support is not compiled into the OpenSSL library against which PHP is linked"); php_stream_close(stream); return NULL; @@ -3720,7 +3738,7 @@ php_stream *php_openssl_ssl_socket_factory(const char *proto, size_t protolen, sslsock->enable_on_connect = 1; sslsock->method = STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT; #else - php_error_docref(NULL, E_WARNING, + php_stream_warn(stream, ProtocolUnsupported, "TLSv1.2 support is not compiled into the OpenSSL library against which PHP is linked"); php_stream_close(stream); return NULL; @@ -3730,7 +3748,7 @@ php_stream *php_openssl_ssl_socket_factory(const char *proto, size_t protolen, sslsock->enable_on_connect = 1; sslsock->method = STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT; #else - php_error_docref(NULL, E_WARNING, + php_stream_warn(stream, ProtocolUnsupported, "TLSv1.3 support is not compiled into the OpenSSL library against which PHP is linked"); php_stream_close(stream); return NULL; diff --git a/ext/standard/streamsfuncs.c b/ext/standard/streamsfuncs.c index bad645f8668a..7962f0f85de3 100644 --- a/ext/standard/streamsfuncs.c +++ b/ext/standard/streamsfuncs.c @@ -325,7 +325,7 @@ PHP_FUNCTION(stream_socket_accept) if (peername) { zend_string_release(peername); } - php_error_docref(NULL, E_WARNING, "Accept failed: %s", errstr ? ZSTR_VAL(errstr) : "Unknown error"); + php_stream_warn(stream, AcceptFailed, "Accept failed: %s", errstr ? ZSTR_VAL(errstr) : "Unknown error"); RETVAL_FALSE; } 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 37f5d39bfa75..6f470c61d1a1 100644 --- a/ext/standard/tests/streams/stream_errors_exception_mode_terminal.phpt +++ b/ext/standard/tests/streams/stream_errors_exception_mode_terminal.phpt @@ -26,6 +26,6 @@ try { ?> --EXPECTF-- Caught: Failed to open stream: operation failed -Code: 20 +Code: 21 Wrapper: PHP Error code name: OpenFailed diff --git a/main/streams/stream_errors.stub.php b/main/streams/stream_errors.stub.php index 2c56932c4850..255c92beb89e 100644 --- a/main/streams/stream_errors.stub.php +++ b/main/streams/stream_errors.stub.php @@ -22,6 +22,7 @@ enum StreamErrorCode case ConnectFailed; case BindFailed; case ListenFailed; + case AcceptFailed; case NotWritable; case NotReadable; @@ -86,6 +87,7 @@ enum StreamErrorCode case InvalidParam; case RedirectLimit; case AuthFailed; + case TimeOut; /* Encoding/decoding/archiving operations */ case ArchivingFailed; diff --git a/main/streams/stream_errors_arginfo.h b/main/streams/stream_errors_arginfo.h index 3a10e9bc5a40..89df622beb05 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: 3e9ee6f0fdd8ecf3ded82728487a9e774137036a + * Stub hash: 4cddf758cc9f2041802d8cbbaaa45593022a5db1 * Has decl header: yes */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_StreamException_getErrors, 0, 0, IS_ARRAY, 0) @@ -38,6 +38,8 @@ static zend_class_entry *register_class_StreamErrorCode(void) zend_enum_add_case_cstr(class_entry, "ListenFailed", NULL); + zend_enum_add_case_cstr(class_entry, "AcceptFailed", NULL); + zend_enum_add_case_cstr(class_entry, "NotWritable", NULL); zend_enum_add_case_cstr(class_entry, "NotReadable", NULL); @@ -146,6 +148,8 @@ static zend_class_entry *register_class_StreamErrorCode(void) zend_enum_add_case_cstr(class_entry, "AuthFailed", NULL); + zend_enum_add_case_cstr(class_entry, "TimeOut", NULL); + zend_enum_add_case_cstr(class_entry, "ArchivingFailed", NULL); zend_enum_add_case_cstr(class_entry, "EncodingFailed", NULL); diff --git a/main/streams/stream_errors_decl.h b/main/streams/stream_errors_decl.h index 4748768195f1..69fe96252b4c 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: 3e9ee6f0fdd8ecf3ded82728487a9e774137036a */ + * Stub hash: 4cddf758cc9f2041802d8cbbaaa45593022a5db1 */ -#ifndef ZEND_STREAM_ERRORS_DECL_3e9ee6f0fdd8ecf3ded82728487a9e774137036a_H -#define ZEND_STREAM_ERRORS_DECL_3e9ee6f0fdd8ecf3ded82728487a9e774137036a_H +#ifndef ZEND_STREAM_ERRORS_DECL_4cddf758cc9f2041802d8cbbaaa45593022a5db1_H +#define ZEND_STREAM_ERRORS_DECL_4cddf758cc9f2041802d8cbbaaa45593022a5db1_H typedef enum zend_enum_StreamErrorCode { ZEND_ENUM_StreamErrorCode_None = 1, @@ -16,74 +16,76 @@ typedef enum zend_enum_StreamErrorCode { ZEND_ENUM_StreamErrorCode_ConnectFailed = 9, ZEND_ENUM_StreamErrorCode_BindFailed = 10, ZEND_ENUM_StreamErrorCode_ListenFailed = 11, - ZEND_ENUM_StreamErrorCode_NotWritable = 12, - ZEND_ENUM_StreamErrorCode_NotReadable = 13, - ZEND_ENUM_StreamErrorCode_Disabled = 14, - ZEND_ENUM_StreamErrorCode_NotFound = 15, - ZEND_ENUM_StreamErrorCode_PermissionDenied = 16, - ZEND_ENUM_StreamErrorCode_AlreadyExists = 17, - ZEND_ENUM_StreamErrorCode_InvalidPath = 18, - ZEND_ENUM_StreamErrorCode_PathTooLong = 19, - ZEND_ENUM_StreamErrorCode_OpenFailed = 20, - ZEND_ENUM_StreamErrorCode_CreateFailed = 21, - ZEND_ENUM_StreamErrorCode_DupFailed = 22, - ZEND_ENUM_StreamErrorCode_UnlinkFailed = 23, - ZEND_ENUM_StreamErrorCode_RenameFailed = 24, - ZEND_ENUM_StreamErrorCode_MkdirFailed = 25, - ZEND_ENUM_StreamErrorCode_RmdirFailed = 26, - ZEND_ENUM_StreamErrorCode_StatFailed = 27, - ZEND_ENUM_StreamErrorCode_MetaFailed = 28, - ZEND_ENUM_StreamErrorCode_ChmodFailed = 29, - ZEND_ENUM_StreamErrorCode_ChownFailed = 30, - ZEND_ENUM_StreamErrorCode_CopyFailed = 31, - ZEND_ENUM_StreamErrorCode_TouchFailed = 32, - ZEND_ENUM_StreamErrorCode_InvalidMode = 33, - ZEND_ENUM_StreamErrorCode_InvalidMeta = 34, - ZEND_ENUM_StreamErrorCode_ModeNotSupported = 35, - ZEND_ENUM_StreamErrorCode_Readonly = 36, - ZEND_ENUM_StreamErrorCode_RecursionDetected = 37, - ZEND_ENUM_StreamErrorCode_NotImplemented = 38, - ZEND_ENUM_StreamErrorCode_NoOpener = 39, - ZEND_ENUM_StreamErrorCode_PersistentNotSupported = 40, - ZEND_ENUM_StreamErrorCode_WrapperNotFound = 41, - ZEND_ENUM_StreamErrorCode_WrapperDisabled = 42, - ZEND_ENUM_StreamErrorCode_ProtocolUnsupported = 43, - ZEND_ENUM_StreamErrorCode_WrapperRegistrationFailed = 44, - ZEND_ENUM_StreamErrorCode_WrapperUnregistrationFailed = 45, - ZEND_ENUM_StreamErrorCode_WrapperRestorationFailed = 46, - ZEND_ENUM_StreamErrorCode_FilterNotFound = 47, - ZEND_ENUM_StreamErrorCode_FilterFailed = 48, - ZEND_ENUM_StreamErrorCode_CastFailed = 49, - ZEND_ENUM_StreamErrorCode_CastNotSupported = 50, - ZEND_ENUM_StreamErrorCode_MakeSeekableFailed = 51, - ZEND_ENUM_StreamErrorCode_BufferedDataLost = 52, - ZEND_ENUM_StreamErrorCode_NetworkSendFailed = 53, - ZEND_ENUM_StreamErrorCode_NetworkRecvFailed = 54, - ZEND_ENUM_StreamErrorCode_SslNotSupported = 55, - ZEND_ENUM_StreamErrorCode_ResumptionFailed = 56, - ZEND_ENUM_StreamErrorCode_SocketPathTooLong = 57, - ZEND_ENUM_StreamErrorCode_OobNotSupported = 58, - ZEND_ENUM_StreamErrorCode_ProtocolError = 59, - ZEND_ENUM_StreamErrorCode_InvalidUrl = 60, - ZEND_ENUM_StreamErrorCode_InvalidResponse = 61, - ZEND_ENUM_StreamErrorCode_InvalidHeader = 62, - ZEND_ENUM_StreamErrorCode_InvalidParam = 63, - ZEND_ENUM_StreamErrorCode_RedirectLimit = 64, - ZEND_ENUM_StreamErrorCode_AuthFailed = 65, - ZEND_ENUM_StreamErrorCode_ArchivingFailed = 66, - ZEND_ENUM_StreamErrorCode_EncodingFailed = 67, - ZEND_ENUM_StreamErrorCode_DecodingFailed = 68, - ZEND_ENUM_StreamErrorCode_InvalidFormat = 69, - ZEND_ENUM_StreamErrorCode_AllocationFailed = 70, - ZEND_ENUM_StreamErrorCode_TemporaryFileFailed = 71, - ZEND_ENUM_StreamErrorCode_LockFailed = 72, - ZEND_ENUM_StreamErrorCode_LockNotSupported = 73, - ZEND_ENUM_StreamErrorCode_UserspaceNotImplemented = 74, - ZEND_ENUM_StreamErrorCode_UserspaceInvalidReturn = 75, - ZEND_ENUM_StreamErrorCode_UserspaceCallFailed = 76, + ZEND_ENUM_StreamErrorCode_AcceptFailed = 12, + ZEND_ENUM_StreamErrorCode_NotWritable = 13, + ZEND_ENUM_StreamErrorCode_NotReadable = 14, + ZEND_ENUM_StreamErrorCode_Disabled = 15, + ZEND_ENUM_StreamErrorCode_NotFound = 16, + ZEND_ENUM_StreamErrorCode_PermissionDenied = 17, + ZEND_ENUM_StreamErrorCode_AlreadyExists = 18, + ZEND_ENUM_StreamErrorCode_InvalidPath = 19, + ZEND_ENUM_StreamErrorCode_PathTooLong = 20, + ZEND_ENUM_StreamErrorCode_OpenFailed = 21, + ZEND_ENUM_StreamErrorCode_CreateFailed = 22, + ZEND_ENUM_StreamErrorCode_DupFailed = 23, + ZEND_ENUM_StreamErrorCode_UnlinkFailed = 24, + ZEND_ENUM_StreamErrorCode_RenameFailed = 25, + ZEND_ENUM_StreamErrorCode_MkdirFailed = 26, + ZEND_ENUM_StreamErrorCode_RmdirFailed = 27, + ZEND_ENUM_StreamErrorCode_StatFailed = 28, + ZEND_ENUM_StreamErrorCode_MetaFailed = 29, + ZEND_ENUM_StreamErrorCode_ChmodFailed = 30, + ZEND_ENUM_StreamErrorCode_ChownFailed = 31, + ZEND_ENUM_StreamErrorCode_CopyFailed = 32, + ZEND_ENUM_StreamErrorCode_TouchFailed = 33, + ZEND_ENUM_StreamErrorCode_InvalidMode = 34, + ZEND_ENUM_StreamErrorCode_InvalidMeta = 35, + ZEND_ENUM_StreamErrorCode_ModeNotSupported = 36, + ZEND_ENUM_StreamErrorCode_Readonly = 37, + ZEND_ENUM_StreamErrorCode_RecursionDetected = 38, + ZEND_ENUM_StreamErrorCode_NotImplemented = 39, + ZEND_ENUM_StreamErrorCode_NoOpener = 40, + ZEND_ENUM_StreamErrorCode_PersistentNotSupported = 41, + ZEND_ENUM_StreamErrorCode_WrapperNotFound = 42, + ZEND_ENUM_StreamErrorCode_WrapperDisabled = 43, + ZEND_ENUM_StreamErrorCode_ProtocolUnsupported = 44, + ZEND_ENUM_StreamErrorCode_WrapperRegistrationFailed = 45, + ZEND_ENUM_StreamErrorCode_WrapperUnregistrationFailed = 46, + ZEND_ENUM_StreamErrorCode_WrapperRestorationFailed = 47, + ZEND_ENUM_StreamErrorCode_FilterNotFound = 48, + ZEND_ENUM_StreamErrorCode_FilterFailed = 49, + ZEND_ENUM_StreamErrorCode_CastFailed = 50, + ZEND_ENUM_StreamErrorCode_CastNotSupported = 51, + ZEND_ENUM_StreamErrorCode_MakeSeekableFailed = 52, + ZEND_ENUM_StreamErrorCode_BufferedDataLost = 53, + ZEND_ENUM_StreamErrorCode_NetworkSendFailed = 54, + ZEND_ENUM_StreamErrorCode_NetworkRecvFailed = 55, + ZEND_ENUM_StreamErrorCode_SslNotSupported = 56, + ZEND_ENUM_StreamErrorCode_ResumptionFailed = 57, + ZEND_ENUM_StreamErrorCode_SocketPathTooLong = 58, + ZEND_ENUM_StreamErrorCode_OobNotSupported = 59, + ZEND_ENUM_StreamErrorCode_ProtocolError = 60, + ZEND_ENUM_StreamErrorCode_InvalidUrl = 61, + ZEND_ENUM_StreamErrorCode_InvalidResponse = 62, + ZEND_ENUM_StreamErrorCode_InvalidHeader = 63, + ZEND_ENUM_StreamErrorCode_InvalidParam = 64, + ZEND_ENUM_StreamErrorCode_RedirectLimit = 65, + ZEND_ENUM_StreamErrorCode_AuthFailed = 66, + ZEND_ENUM_StreamErrorCode_TimeOut = 67, + ZEND_ENUM_StreamErrorCode_ArchivingFailed = 68, + ZEND_ENUM_StreamErrorCode_EncodingFailed = 69, + ZEND_ENUM_StreamErrorCode_DecodingFailed = 70, + ZEND_ENUM_StreamErrorCode_InvalidFormat = 71, + ZEND_ENUM_StreamErrorCode_AllocationFailed = 72, + ZEND_ENUM_StreamErrorCode_TemporaryFileFailed = 73, + ZEND_ENUM_StreamErrorCode_LockFailed = 74, + ZEND_ENUM_StreamErrorCode_LockNotSupported = 75, + ZEND_ENUM_StreamErrorCode_UserspaceNotImplemented = 76, + ZEND_ENUM_StreamErrorCode_UserspaceInvalidReturn = 77, + ZEND_ENUM_StreamErrorCode_UserspaceCallFailed = 78, } zend_enum_StreamErrorCode; -#define ZEND_ENUM_StreamErrorCode_CASE_COUNT 76 +#define ZEND_ENUM_StreamErrorCode_CASE_COUNT 78 #ifdef ZEND_ENUM_StreamErrorCode_USE_NAME_TABLE static const char *zend_enum_StreamErrorCode_case_names[ZEND_ENUM_StreamErrorCode_CASE_COUNT + 1] = { @@ -98,6 +100,7 @@ static const char *zend_enum_StreamErrorCode_case_names[ZEND_ENUM_StreamErrorCod [ZEND_ENUM_StreamErrorCode_ConnectFailed] = "ConnectFailed", [ZEND_ENUM_StreamErrorCode_BindFailed] = "BindFailed", [ZEND_ENUM_StreamErrorCode_ListenFailed] = "ListenFailed", + [ZEND_ENUM_StreamErrorCode_AcceptFailed] = "AcceptFailed", [ZEND_ENUM_StreamErrorCode_NotWritable] = "NotWritable", [ZEND_ENUM_StreamErrorCode_NotReadable] = "NotReadable", [ZEND_ENUM_StreamErrorCode_Disabled] = "Disabled", @@ -152,6 +155,7 @@ static const char *zend_enum_StreamErrorCode_case_names[ZEND_ENUM_StreamErrorCod [ZEND_ENUM_StreamErrorCode_InvalidParam] = "InvalidParam", [ZEND_ENUM_StreamErrorCode_RedirectLimit] = "RedirectLimit", [ZEND_ENUM_StreamErrorCode_AuthFailed] = "AuthFailed", + [ZEND_ENUM_StreamErrorCode_TimeOut] = "TimeOut", [ZEND_ENUM_StreamErrorCode_ArchivingFailed] = "ArchivingFailed", [ZEND_ENUM_StreamErrorCode_EncodingFailed] = "EncodingFailed", [ZEND_ENUM_StreamErrorCode_DecodingFailed] = "DecodingFailed", @@ -180,4 +184,4 @@ typedef enum zend_enum_StreamErrorStore { ZEND_ENUM_StreamErrorStore_All = 5, } zend_enum_StreamErrorStore; -#endif /* ZEND_STREAM_ERRORS_DECL_3e9ee6f0fdd8ecf3ded82728487a9e774137036a_H */ +#endif /* ZEND_STREAM_ERRORS_DECL_4cddf758cc9f2041802d8cbbaaa45593022a5db1_H */ From 895c2af4d4846819e84762297d810cb29bc9fe3a Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Sun, 28 Jun 2026 20:36:14 +0100 Subject: [PATCH 3/3] ext/phar: refactor {de}compression filter name APIs (#22502) And clean-up usage sites as some of them shouldn't even be possible in the first place --- ext/phar/phar.c | 4 +++- ext/phar/phar_internal.h | 4 ++-- ext/phar/phar_object.c | 14 +++++--------- ext/phar/util.c | 24 +++++++++++------------- ext/phar/zip.c | 5 +++-- 5 files changed, 24 insertions(+), 27 deletions(-) diff --git a/ext/phar/phar.c b/ext/phar/phar.c index ee12c5b91feb..c64c448c52a5 100644 --- a/ext/phar/phar.c +++ b/ext/phar/phar.c @@ -2724,7 +2724,9 @@ ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) int phar_flush_ex(phar_archive_data *phar, zen entry->compressed_filesize = entry->uncompressed_filesize; continue; } - filter = php_stream_filter_create(phar_compress_filter(entry, false), NULL, 0); + const char *compression_filter_name = phar_get_compress_filter_name(entry); + ZEND_ASSERT(compression_filter_name && "Must have as this has a compression flag set"); + filter = php_stream_filter_create(compression_filter_name, NULL, false); if (!filter) { if (must_close_old_file) { php_stream_close(oldfile); diff --git a/ext/phar/phar_internal.h b/ext/phar/phar_internal.h index f175fb7b9d60..a7a5581e1606 100644 --- a/ext/phar/phar_internal.h +++ b/ext/phar/phar_internal.h @@ -442,8 +442,8 @@ ZEND_ATTRIBUTE_NONNULL zend_string* phar_create_signature(phar_archive_data *pha /* utility functions */ zend_string *phar_create_default_stub(const zend_string *php_index_str, const zend_string *web_index_str, char **error); -const char *phar_decompress_filter(const phar_entry_info *entry, bool return_unknown); -const char *phar_compress_filter(const phar_entry_info *entry, bool return_unknown); +const char *phar_get_decompress_filter_name(const phar_entry_info *entry); +const char *phar_get_compress_filter_name(const phar_entry_info *entry); /* void phar_remove_virtual_dirs(phar_archive_data *phar, char *filename, size_t filename_len); */ void phar_add_virtual_dirs(phar_archive_data *phar, const char *filename, size_t filename_len); diff --git a/ext/phar/phar_object.c b/ext/phar/phar_object.c index 7eb8392e6c69..9859551b3ccf 100644 --- a/ext/phar/phar_object.c +++ b/ext/phar/phar_object.c @@ -3865,15 +3865,11 @@ PHP_METHOD(Phar, getStub) RETURN_THROWS(); } if (stub->flags & PHAR_ENT_COMPRESSION_MASK) { - const char *filter_name = phar_decompress_filter(stub, false); - - if (filter_name != NULL) { - filter = php_stream_filter_create(filter_name, NULL, php_stream_is_persistent(fp)); - } else { - filter = NULL; - } - if (!filter) { - zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0, "phar error: unable to read stub of phar \"%s\" (cannot create %s filter)", ZSTR_VAL(phar_obj->archive->fname), phar_decompress_filter(stub, true)); + const char *decompression_filter_name = phar_get_decompress_filter_name(stub); + ZEND_ASSERT(decompression_filter_name && "Must have as this has a decompression flag set"); + filter = php_stream_filter_create(decompression_filter_name, NULL, php_stream_is_persistent(fp)); + if (UNEXPECTED(filter == NULL)) { + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0, "phar error: unable to read stub of phar \"%s\" (cannot create %s filter)", ZSTR_VAL(phar_obj->archive->fname), decompression_filter_name); RETURN_THROWS(); } php_stream_filter_append(&fp->readfilters, filter); diff --git a/ext/phar/util.c b/ext/phar/util.c index 2962f778b274..1f94be5a269d 100644 --- a/ext/phar/util.c +++ b/ext/phar/util.c @@ -787,7 +787,6 @@ static void phar_set_fp_type(phar_entry_info *entry, enum phar_fp_type type, zen */ ZEND_ATTRIBUTE_NONNULL zend_result phar_open_entry_fp(phar_entry_info *entry, char **error, bool follow_links) /* {{{ */ { - php_stream_filter *filter; phar_archive_data *phar = entry->phar; zend_off_t loc; php_stream *ufp; @@ -852,15 +851,16 @@ ZEND_ATTRIBUTE_NONNULL zend_result phar_open_entry_fp(phar_entry_info *entry, ch ufp = phar_get_entrypufp(entry); - const char *filter_name = phar_decompress_filter(entry, false); - if (filter_name != NULL) { - filter = php_stream_filter_create(filter_name, NULL, 0); - } else { - filter = NULL; + const char *decompression_filter_name = phar_get_decompress_filter_name(entry); + if (UNEXPECTED(!decompression_filter_name)) { + spprintf(error, 4096, "phar error: unable to read phar \"%s\" (file \"%s\" is compressed with an unknown compression algorithm)", ZSTR_VAL(phar->fname), ZSTR_VAL(entry->filename)); + return FAILURE; } + php_stream_filter *filter = php_stream_filter_create(decompression_filter_name, NULL, 0); + if (!filter) { - spprintf(error, 4096, "phar error: unable to read phar \"%s\" (cannot create %s filter while decompressing file \"%s\")", ZSTR_VAL(phar->fname), phar_decompress_filter(entry, true), ZSTR_VAL(entry->filename)); + spprintf(error, 4096, "phar error: unable to read phar \"%s\" (cannot create %s filter while decompressing file \"%s\")", ZSTR_VAL(phar->fname), decompression_filter_name, ZSTR_VAL(entry->filename)); return FAILURE; } @@ -1115,7 +1115,7 @@ phar_archive_data* phar_get_archive(const char *fname, size_t fname_len, const c /** * Determine which stream compression filter (if any) we need to read this file */ -const char * phar_compress_filter(const phar_entry_info *entry, bool return_unknown) /* {{{ */ +const char * phar_get_compress_filter_name(const phar_entry_info *entry) { switch (entry->flags & PHAR_ENT_COMPRESSION_MASK) { case PHAR_ENT_COMPRESSED_GZ: @@ -1123,15 +1123,14 @@ const char * phar_compress_filter(const phar_entry_info *entry, bool return_unkn case PHAR_ENT_COMPRESSED_BZ2: return "bzip2.compress"; default: - return return_unknown ? "unknown" : NULL; + return NULL; } } -/* }}} */ /** * Determine which stream decompression filter (if any) we need to read this file */ -const char * phar_decompress_filter(const phar_entry_info *entry, bool return_unknown) /* {{{ */ +const char * phar_get_decompress_filter_name(const phar_entry_info *entry) { uint32_t flags; @@ -1147,10 +1146,9 @@ const char * phar_decompress_filter(const phar_entry_info *entry, bool return_un case PHAR_ENT_COMPRESSED_BZ2: return "bzip2.decompress"; default: - return return_unknown ? "unknown" : NULL; + return NULL; } } -/* }}} */ /** * retrieve information on a file contained within a phar, or null if it ain't there diff --git a/ext/phar/zip.c b/ext/phar/zip.c index 5aa3f552b2ab..3085ee80c9aa 100644 --- a/ext/phar/zip.c +++ b/ext/phar/zip.c @@ -935,7 +935,6 @@ static int phar_zip_changed_apply_int(phar_entry_info *entry, void *arg) /* {{{ /* do extra field for perms later */ if (entry->is_modified) { - php_stream_filter *filter; php_stream *efp; if (entry->is_dir) { @@ -981,7 +980,9 @@ static int phar_zip_changed_apply_int(phar_entry_info *entry, void *arg) /* {{{ goto not_compressed; } - filter = php_stream_filter_create(phar_compress_filter(entry, false), NULL, 0); + const char *compression_filter_name = phar_get_compress_filter_name(entry); + ZEND_ASSERT(compression_filter_name && "Must have as this has a compression flag set"); + php_stream_filter *filter = php_stream_filter_create(compression_filter_name, NULL, false); if (!filter) { if (entry->flags & PHAR_ENT_COMPRESSED_GZ) {