Commit fb687954585 for php.net

commit fb6879545855c5fc627aaad5ea728f492469bec2
Merge: 9b383fa4920 b2922543bfd
Author: David Carlier <devnexen@gmail.com>
Date:   Thu Aug 13 22:07:42 2026 +0100

    Merge branch 'PHP-8.5'

    * PHP-8.5:
      ext/zip: fix extractTo()/getFrom*() success on CRC-corrupted entries

diff --cc ext/zip/php_zip.c
index ff355768e26,2ee9f57129e..7488be7828e
--- a/ext/zip/php_zip.c
+++ b/ext/zip/php_zip.c
@@@ -138,8 -126,35 +138,32 @@@ static char * php_zip_make_relative_pat
  }
  /* }}} */

 -# define CWD_STATE_ALLOC(l) emalloc(l)
 -# define CWD_STATE_FREE(s)  efree(s)
 -
+ /* {{{ php_zip_file_error
+  Entry error code, plus its message when message is not NULL.
+  zip_error_t and its accessors only exist since libzip 1.0. */
+ static int php_zip_file_error(struct zip_file *zf, const char **message)
+ {
+ #if LIBZIP_VERSION_MAJOR < 1
+ 	int zep, syp;
+
+ 	zip_file_error_get(zf, &zep, &syp);
+ 	if (message) {
+ 		*message = zip_file_strerror(zf);
+ 	}
+ 	return zep;
+ #else
+ 	zip_error_t *err = zip_file_get_error(zf);
+
+ 	if (message) {
+ 		*message = zip_error_strerror(err);
+ 	}
+ 	return zip_error_code_zip(err);
+ #endif
+ }
+ /* }}} */
+
  /* {{{ php_zip_extract_file */
 -static int php_zip_extract_file(struct zip * za, char *dest, const char *file, size_t file_len, zip_int64_t idx)
 +static bool php_zip_extract_file(struct zip * za, char *dest, const char *file, size_t file_len, zip_int64_t idx)
  {
  	php_stream_statbuf ssb;
  	struct zip_file *zf;
@@@ -2923,9 -2956,41 +2957,41 @@@ static void php_zip_get_from(INTERNAL_F
  		RETURN_FALSE;
  	}

 -	buffer = zend_string_safe_alloc(1, len, 0, 0);
 +	buffer = zend_string_safe_alloc(1, len, 0, false);
- 	zip_int64_t n = zip_fread(zf, ZSTR_VAL(buffer), ZSTR_LEN(buffer));
- 	if (n < 1) {
+
+ 	/* zip_fread() may return short reads, a truncated entry must not pass for a complete one. */
+ 	zip_int64_t n = 0;
+ 	while ((zip_uint64_t)n < ZSTR_LEN(buffer)) {
+ 		zip_int64_t rd = zip_fread(zf, ZSTR_VAL(buffer) + n, ZSTR_LEN(buffer) - n);
+
+ 		if (rd < 0) {
+ 			n = -1;
+ 			break;
+ 		}
+ 		if (rd == 0) {
+ 			break;
+ 		}
+ 		n += rd;
+ 	}
+
+ 	if (n >= 0 && (zip_uint64_t)n == sb.size) {
+ 		/* The whole entry has been consumed, read past its last byte so that
+ 		 * libzip reaches the end of the stream and validates the CRC. */
+ 		char tmp;
+ 		if (zip_fread(zf, &tmp, 1) < 0) {
+ 			n = -1;
+ 		}
+ 	}
+ 	if (n < 0) {
+ 		const char *message;
+
+ 		php_zip_file_error(zf, &message);
+ 		php_error_docref(NULL, E_WARNING, "Cannot read entry: %s", message);
+ 		zip_fclose(zf);
+ 		zend_string_efree(buffer);
+ 		RETURN_FALSE;
+ 	}
+ 	if (n == 0) {
  		zip_fclose(zf);
  		zend_string_efree(buffer);
  		RETURN_EMPTY_STRING();