From 6ac29ec0742bdae3f864301db318a89553fa6ed0 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Thu, 16 Oct 2025 00:40:42 +0100 Subject: [PATCH 01/12] ext/phar: remove unused parameters for phar_do_403() --- ext/phar/phar_object.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/phar/phar_object.c b/ext/phar/phar_object.c index 8a7cf236b097..3dc8b40a32c6 100644 --- a/ext/phar/phar_object.c +++ b/ext/phar/phar_object.c @@ -311,7 +311,7 @@ static int phar_file_action(phar_archive_data *phar, phar_entry_info *info, char } /* }}} */ -static void phar_do_403(char *entry, size_t entry_len) /* {{{ */ +static void phar_do_403(void) /* {{{ */ { sapi_header_line ctr = {0}; @@ -723,7 +723,7 @@ PHP_METHOD(Phar, webPhar) break; case IS_TRUE: case IS_FALSE: - phar_do_403(entry, entry_len); + phar_do_403(); if (free_pathinfo) { efree(path_info); From c0856bc729ffef65a437eef4149465d0e795f662 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Wed, 15 Oct 2025 23:31:27 +0100 Subject: [PATCH 02/12] ext/phar: remove unused parameters for phar_do_404() --- ext/phar/phar_object.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ext/phar/phar_object.c b/ext/phar/phar_object.c index 3dc8b40a32c6..73e0daf1ccae 100644 --- a/ext/phar/phar_object.c +++ b/ext/phar/phar_object.c @@ -325,7 +325,7 @@ static void phar_do_403(void) /* {{{ */ } /* }}} */ -static void phar_do_404(phar_archive_data *phar, char *fname, size_t fname_len, char *f404, size_t f404_len, char *entry, size_t entry_len) /* {{{ */ +static void phar_do_404(phar_archive_data *phar, char *fname, size_t fname_len, char *f404, size_t f404_len) /* {{{ */ { sapi_header_line ctr = {0}; phar_entry_info *info; @@ -769,7 +769,7 @@ PHP_METHOD(Phar, webPhar) if (FAILURE == phar_get_archive(&phar, fname, fname_len, NULL, 0, NULL) || (info = phar_get_entry_info(phar, entry, entry_len, NULL, false)) == NULL) { - phar_do_404(phar, fname, fname_len, f404, f404_len, entry, entry_len); + phar_do_404(phar, fname, fname_len, f404, f404_len); if (free_pathinfo) { efree(path_info); @@ -815,7 +815,7 @@ PHP_METHOD(Phar, webPhar) if (FAILURE == phar_get_archive(&phar, fname, fname_len, NULL, 0, NULL) || (info = phar_get_entry_info(phar, entry, entry_len, NULL, false)) == NULL) { - phar_do_404(phar, fname, fname_len, f404, f404_len, entry, entry_len); + phar_do_404(phar, fname, fname_len, f404, f404_len); zend_bailout(); } From d7eef8c4305219f7e2a23dea0bd7ca1702609ff2 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Thu, 16 Oct 2025 00:42:35 +0100 Subject: [PATCH 03/12] ext/phar: use zend_string for f404 param of phar_do_404() --- ext/phar/phar_object.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/ext/phar/phar_object.c b/ext/phar/phar_object.c index 73e0daf1ccae..e4edfee5a68b 100644 --- a/ext/phar/phar_object.c +++ b/ext/phar/phar_object.c @@ -325,16 +325,16 @@ static void phar_do_403(void) /* {{{ */ } /* }}} */ -static void phar_do_404(phar_archive_data *phar, char *fname, size_t fname_len, char *f404, size_t f404_len) /* {{{ */ +static void phar_do_404(phar_archive_data *phar, char *fname, size_t fname_len, zend_string *f404) /* {{{ */ { sapi_header_line ctr = {0}; phar_entry_info *info; - if (phar && f404_len) { - info = phar_get_entry_info(phar, f404, f404_len, NULL, true); + if (phar && f404 && ZSTR_LEN(f404)) { + info = phar_get_entry_info(phar, ZSTR_VAL(f404), ZSTR_LEN(f404), NULL, true); if (info) { - phar_file_action(phar, info, "text/html", PHAR_MIME_PHP, f404, f404_len, fname, NULL, NULL, 0); + phar_file_action(phar, info, "text/html", PHAR_MIME_PHP, ZSTR_VAL(f404), ZSTR_LEN(f404), fname, NULL, NULL, 0); return; } } @@ -559,8 +559,9 @@ PHP_METHOD(Phar, webPhar) zval *mimeoverride = NULL; zend_fcall_info rewrite_fci = {0}; zend_fcall_info_cache rewrite_fcc; - char *alias = NULL, *error, *index_php = NULL, *f404 = NULL, *ru = NULL; - size_t alias_len = 0, f404_len = 0, free_pathinfo = 0; + char *alias = NULL, *error, *index_php = NULL, *ru = NULL; + size_t alias_len = 0, free_pathinfo = 0; + zend_string *f404 = NULL; size_t ru_len = 0; char *fname, *path_info, *mime_type = NULL, *entry, *pt; const char *basename; @@ -571,7 +572,7 @@ PHP_METHOD(Phar, webPhar) phar_entry_info *info = NULL; size_t sapi_mod_name_len = strlen(sapi_module.name); - if (zend_parse_parameters(ZEND_NUM_ARGS(), "|s!s!s!af!", &alias, &alias_len, &index_php, &index_php_len, &f404, &f404_len, &mimeoverride, &rewrite_fci, &rewrite_fcc) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "|s!s!S!af!", &alias, &alias_len, &index_php, &index_php_len, &f404, &mimeoverride, &rewrite_fci, &rewrite_fcc) == FAILURE) { RETURN_THROWS(); } @@ -769,7 +770,7 @@ PHP_METHOD(Phar, webPhar) if (FAILURE == phar_get_archive(&phar, fname, fname_len, NULL, 0, NULL) || (info = phar_get_entry_info(phar, entry, entry_len, NULL, false)) == NULL) { - phar_do_404(phar, fname, fname_len, f404, f404_len); + phar_do_404(phar, fname, fname_len, f404); if (free_pathinfo) { efree(path_info); @@ -815,7 +816,7 @@ PHP_METHOD(Phar, webPhar) if (FAILURE == phar_get_archive(&phar, fname, fname_len, NULL, 0, NULL) || (info = phar_get_entry_info(phar, entry, entry_len, NULL, false)) == NULL) { - phar_do_404(phar, fname, fname_len, f404, f404_len); + phar_do_404(phar, fname, fname_len, f404); zend_bailout(); } From 8fa09cd252cfe63f045c0876fd63e8c4b0d023cd Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Wed, 15 Oct 2025 23:37:41 +0100 Subject: [PATCH 04/12] ext/phar: Use RETURN_BOOL() when possible --- ext/phar/phar_object.c | 44 ++++++++++++------------------------------ 1 file changed, 12 insertions(+), 32 deletions(-) diff --git a/ext/phar/phar_object.c b/ext/phar/phar_object.c index e4edfee5a68b..171015582796 100644 --- a/ext/phar/phar_object.c +++ b/ext/phar/phar_object.c @@ -1030,23 +1030,11 @@ PHP_METHOD(Phar, canCompress) phar_request_initialize(); switch (method) { case PHAR_ENT_COMPRESSED_GZ: - if (PHAR_G(has_zlib)) { - RETURN_TRUE; - } else { - RETURN_FALSE; - } + RETURN_BOOL(PHAR_G(has_zlib)); case PHAR_ENT_COMPRESSED_BZ2: - if (PHAR_G(has_bz2)) { - RETURN_TRUE; - } else { - RETURN_FALSE; - } + RETURN_BOOL(PHAR_G(has_bz2)); default: - if (PHAR_G(has_zlib) || PHAR_G(has_bz2)) { - RETURN_TRUE; - } else { - RETURN_FALSE; - } + RETURN_BOOL(PHAR_G(has_zlib) || PHAR_G(has_bz2)); } } /* }}} */ @@ -2577,11 +2565,8 @@ PHP_METHOD(Phar, isWritable) } if (SUCCESS != php_stream_stat_path(phar_obj->archive->fname, &ssb)) { - if (phar_obj->archive->is_brandnew) { - /* assume it works if the file doesn't exist yet */ - RETURN_TRUE; - } - RETURN_FALSE; + /* assume it works if the file doesn't exist yet */ + RETURN_BOOL(phar_obj->archive->is_brandnew); } RETURN_BOOL((ssb.sb.st_mode & (S_IWOTH | S_IWGRP | S_IWUSR)) != 0); @@ -3503,7 +3488,6 @@ PHP_METHOD(Phar, copy) PHP_METHOD(Phar, offsetExists) { zend_string *file_name; - phar_entry_info *entry; if (zend_parse_parameters(ZEND_NUM_ARGS(), "P", &file_name) == FAILURE) { RETURN_THROWS(); @@ -3511,19 +3495,15 @@ PHP_METHOD(Phar, offsetExists) PHAR_ARCHIVE_OBJECT(); - if (zend_hash_exists(&phar_obj->archive->manifest, file_name)) { - if (NULL != (entry = zend_hash_find_ptr(&phar_obj->archive->manifest, file_name))) { - if (entry->is_deleted) { - /* entry is deleted, but has not been flushed to disk yet */ - RETURN_FALSE; - } - } - - if (zend_string_starts_with_literal(file_name, ".phar")) { - /* none of these are real files, so they don't exist */ + const phar_entry_info *entry = zend_hash_find_ptr(&phar_obj->archive->manifest, file_name); + if (entry != NULL) { + if (entry->is_deleted) { + /* entry is deleted, but has not been flushed to disk yet */ RETURN_FALSE; } - RETURN_TRUE; + + /* none of these are real files, so they don't exist */ + RETURN_BOOL(!zend_string_starts_with_literal(file_name, ".phar")); } else { /* If the info class is not based on PharFileInfo, directories are not directly instantiable */ if (UNEXPECTED(!instanceof_function(phar_obj->spl.info_class, phar_ce_entry))) { From 44a863a805819c4bf2f9fbd0b17051f5b11f4789 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Thu, 16 Oct 2025 00:03:28 +0100 Subject: [PATCH 05/12] ext/phar: Do not aquire lifetime of basename parameter in phar_file_action() This is incredibly confusing. --- ext/phar/phar_object.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/ext/phar/phar_object.c b/ext/phar/phar_object.c index 171015582796..6741ca40f566 100644 --- a/ext/phar/phar_object.c +++ b/ext/phar/phar_object.c @@ -168,7 +168,6 @@ static int phar_file_action(phar_archive_data *phar, phar_entry_info *info, char switch (code) { case PHAR_MIME_PHPS: - efree(basename); /* highlight source */ if (entry[0] == '/') { spprintf(&name, 4096, "phar://%s%s", arch, entry); @@ -186,7 +185,6 @@ static int phar_file_action(phar_archive_data *phar, phar_entry_info *info, char zend_bailout(); case PHAR_MIME_OTHER: /* send headers, output file contents */ - efree(basename); ctr.line_len = spprintf((char **) &(ctr.line), 0, "Content-type: %s", mime_type); sapi_header_op(SAPI_HEADER_REPLACE, &ctr); efree((void *) ctr.line); @@ -230,7 +228,6 @@ static int phar_file_action(phar_archive_data *phar, phar_entry_info *info, char case PHAR_MIME_PHP: if (basename) { phar_mung_server_vars(arch, entry, entry_len, basename, ru_len); - efree(basename); } if (entry[0] == '/') { @@ -870,6 +867,7 @@ PHP_METHOD(Phar, webPhar) code = phar_file_type(&PHAR_G(mime_types), entry, &mime_type); } phar_file_action(phar, info, mime_type, code, entry, entry_len, fname, pt, ru, ru_len); + efree(pt); finish: ; #ifdef PHP_WIN32 From 0b37777592f20f42522e94335d2ef778005ec07a Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Thu, 16 Oct 2025 00:10:57 +0100 Subject: [PATCH 06/12] ext/phar/phar_object.c: add some const qualifiers --- ext/phar/phar_object.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ext/phar/phar_object.c b/ext/phar/phar_object.c index 6741ca40f566..e1c18cd4bac6 100644 --- a/ext/phar/phar_object.c +++ b/ext/phar/phar_object.c @@ -45,7 +45,7 @@ static zend_class_entry *phar_ce_entry; RETURN_THROWS(); \ } -static int phar_file_type(HashTable *mimes, char *file, char **mime_type) /* {{{ */ +static int phar_file_type(const HashTable *mimes, const char *file, char **mime_type) /* {{{ */ { char *ext; phar_mime_type *mime; @@ -65,7 +65,7 @@ static int phar_file_type(HashTable *mimes, char *file, char **mime_type) /* {{{ } /* }}} */ -static void phar_mung_server_vars(char *fname, char *entry, size_t entry_len, char *basename, size_t request_uri_len) /* {{{ */ +static void phar_mung_server_vars(char *fname, char *entry, size_t entry_len, const char *basename, size_t request_uri_len) /* {{{ */ { HashTable *_SERVER; zval *stuff; @@ -151,7 +151,7 @@ static void phar_mung_server_vars(char *fname, char *entry, size_t entry_len, ch } /* }}} */ -static int phar_file_action(phar_archive_data *phar, phar_entry_info *info, char *mime_type, int code, char *entry, size_t entry_len, char *arch, char *basename, char *ru, size_t ru_len) /* {{{ */ +static int phar_file_action(phar_archive_data *phar, phar_entry_info *info, char *mime_type, int code, char *entry, size_t entry_len, char *arch, const char *basename, char *ru, size_t ru_len) /* {{{ */ { char *name = NULL, buf[8192]; const char *cwd; @@ -349,7 +349,7 @@ static void phar_do_404(phar_archive_data *phar, char *fname, size_t fname_len, /* post-process REQUEST_URI and retrieve the actual request URI. This is for cases like http://localhost/blah.phar/path/to/file.php/extra/stuff which calls "blah.phar" file "path/to/file.php" with PATH_INFO "/extra/stuff" */ -static void phar_postprocess_ru_web(char *fname, size_t fname_len, char **entry, size_t *entry_len, char **ru, size_t *ru_len) /* {{{ */ +static void phar_postprocess_ru_web(const char *fname, size_t fname_len, char **entry, size_t *entry_len, char **ru, size_t *ru_len) /* {{{ */ { char *e = *entry + 1, *u = NULL, *u1 = NULL, *saveu = NULL; size_t e_len = *entry_len - 1, u_len = 0; @@ -627,7 +627,7 @@ PHP_METHOD(Phar, webPhar) || (sapi_mod_name_len == sizeof("litespeed") - 1 && !strncmp(sapi_module.name, "litespeed", sizeof("litespeed") - 1))) { if (Z_TYPE(PG(http_globals)[TRACK_VARS_SERVER]) != IS_UNDEF) { - HashTable *_server = Z_ARRVAL(PG(http_globals)[TRACK_VARS_SERVER]); + const HashTable *_server = Z_ARRVAL(PG(http_globals)[TRACK_VARS_SERVER]); zval *z_script_name, *z_path_info; if (NULL == (z_script_name = zend_hash_str_find(_server, "SCRIPT_NAME", sizeof("SCRIPT_NAME")-1)) || @@ -3114,7 +3114,7 @@ static int phar_set_compression(zval *zv, void *argument) /* {{{ */ static int phar_test_compression(zval *zv, void *argument) /* {{{ */ { - phar_entry_info *entry = (phar_entry_info *)Z_PTR_P(zv); + const phar_entry_info *entry = Z_PTR_P(zv); if (entry->is_deleted) { return ZEND_HASH_APPLY_KEEP; From 3828b2426be742f5cc80512af26b5c15806f4122 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Thu, 16 Oct 2025 00:56:10 +0100 Subject: [PATCH 07/12] ext/phar: Refactor phar_create_default_stub() --- ext/phar/phar.c | 50 ++++++++++++++++++++++------------------ ext/phar/phar_internal.h | 2 +- ext/phar/phar_object.c | 12 +++++----- 3 files changed, 35 insertions(+), 29 deletions(-) diff --git a/ext/phar/phar.c b/ext/phar/phar.c index cec38aa33533..f31a4f841225 100644 --- a/ext/phar/phar.c +++ b/ext/phar/phar.c @@ -2453,42 +2453,48 @@ static int phar_flush_clean_deleted_apply(zval *zv) /* {{{ */ #include "stub.h" /* Generated phar_get_stub() function from makestub.php script */ -zend_string *phar_create_default_stub(const char *index_php, const char *web_index, char **error) /* {{{ */ +zend_string *phar_create_default_stub(const zend_string *php_index_str, const zend_string *web_index_str, char **error) /* {{{ */ { - size_t index_len, web_len; + const char *php_index; + const char *web_index; + size_t php_len, web_len; if (error) { *error = NULL; } - if (!index_php) { - index_php = "index.php"; - } - - if (!web_index) { - web_index = "index.php"; - } - - index_len = strlen(index_php); - web_len = strlen(web_index); - - if (index_len > 400) { - /* ridiculous size not allowed for index.php startup filename */ - if (error) { - spprintf(error, 0, "Illegal filename passed in for stub creation, was %zd characters long, and only 400 or less is allowed", index_len); + if (!php_index_str) { + php_index = "index.php"; + php_len = strlen("index.php"); + } else { + php_index = ZSTR_VAL(php_index_str); + php_len = ZSTR_LEN(php_index_str); + if (php_len > 400) { + /* ridiculous size not allowed for index.php startup filename */ + if (error) { + spprintf(error, 0, "Illegal filename passed in for stub creation, was %zd characters long, and only 400 or less is allowed", php_len); + } return NULL; } } - if (web_len > 400) { - /* ridiculous size not allowed for index.php startup filename */ - if (error) { - spprintf(error, 0, "Illegal web filename passed in for stub creation, was %zd characters long, and only 400 or less is allowed", web_len); + if (!web_index_str) { + web_index = "index.php"; + web_len = strlen("index.php"); + } else { + web_index = ZSTR_VAL(web_index_str); + web_len = ZSTR_LEN(web_index_str); + + if (web_len > 400) { + /* ridiculous size not allowed for index.php startup filename */ + if (error) { + spprintf(error, 0, "Illegal web filename passed in for stub creation, was %zd characters long, and only 400 or less is allowed", web_len); + } return NULL; } } - return phar_get_stub(index_php, web_index, index_len+1, web_len+1); + return phar_get_stub(php_index, web_index, php_len+1, web_len+1); } /* }}} */ diff --git a/ext/phar/phar_internal.h b/ext/phar/phar_internal.h index 232ba579d7f0..bd3d7158c8e8 100644 --- a/ext/phar/phar_internal.h +++ b/ext/phar/phar_internal.h @@ -415,7 +415,7 @@ zend_result phar_verify_signature(php_stream *fp, size_t end_of_phar, uint32_t s ZEND_ATTRIBUTE_NONNULL zend_result phar_create_signature(phar_archive_data *phar, php_stream *fp, char **signature, size_t *signature_length, char **error); /* utility functions */ -zend_string *phar_create_default_stub(const char *index_php, const char *web_index, char **error); +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); diff --git a/ext/phar/phar_object.c b/ext/phar/phar_object.c index e1c18cd4bac6..58c614045188 100644 --- a/ext/phar/phar_object.c +++ b/ext/phar/phar_object.c @@ -946,11 +946,11 @@ PHP_METHOD(Phar, interceptFileFuncs) */ PHP_METHOD(Phar, createDefaultStub) { - char *index = NULL, *webindex = NULL, *error; + zend_string *index = NULL, *webindex = NULL; + char *error; zend_string *stub; - size_t index_len = 0, webindex_len = 0; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "|p!p!", &index, &index_len, &webindex, &webindex_len) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "|P!P!", &index, &webindex) == FAILURE) { RETURN_THROWS(); } @@ -2914,12 +2914,11 @@ PHP_METHOD(Phar, setStub) */ PHP_METHOD(Phar, setDefaultStub) { - char *index = NULL, *webindex = NULL, *error = NULL; + zend_string *index = NULL, *webindex = NULL; zend_string *stub = NULL; - size_t index_len = 0, webindex_len = 0; bool created_stub = false; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "|s!s!", &index, &index_len, &webindex, &webindex_len) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "|P!P!", &index, &webindex) == FAILURE) { RETURN_THROWS(); } @@ -2947,6 +2946,7 @@ PHP_METHOD(Phar, setDefaultStub) RETURN_THROWS(); } + char *error = NULL; if (!phar_obj->archive->is_tar && !phar_obj->archive->is_zip) { stub = phar_create_default_stub(index, webindex, &error); From ad9c60f995c3f9ff088398d73971c39a926022f8 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Thu, 16 Oct 2025 01:33:09 +0100 Subject: [PATCH 08/12] ext/phar: start refactoring phar_postprocess_ru_web() --- ext/phar/phar_object.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ext/phar/phar_object.c b/ext/phar/phar_object.c index 58c614045188..6981d7c026d1 100644 --- a/ext/phar/phar_object.c +++ b/ext/phar/phar_object.c @@ -349,9 +349,10 @@ static void phar_do_404(phar_archive_data *phar, char *fname, size_t fname_len, /* post-process REQUEST_URI and retrieve the actual request URI. This is for cases like http://localhost/blah.phar/path/to/file.php/extra/stuff which calls "blah.phar" file "path/to/file.php" with PATH_INFO "/extra/stuff" */ -static void phar_postprocess_ru_web(const char *fname, size_t fname_len, char **entry, size_t *entry_len, char **ru, size_t *ru_len) /* {{{ */ +static void phar_postprocess_ru_web(const char *fname, size_t fname_len, const char *entry, size_t *entry_len, char **ru, size_t *ru_len) /* {{{ */ { - char *e = *entry + 1, *u = NULL, *u1 = NULL, *saveu = NULL; + const char *e = entry + 1; + char *u = NULL, *u1 = NULL, *saveu = NULL; size_t e_len = *entry_len - 1, u_len = 0; phar_archive_data *pphar; @@ -746,7 +747,7 @@ PHP_METHOD(Phar, webPhar) } if (entry_len) { - phar_postprocess_ru_web(fname, fname_len, &entry, &entry_len, &ru, &ru_len); + phar_postprocess_ru_web(fname, fname_len, entry, &entry_len, &ru, &ru_len); } if (!entry_len || (entry_len == 1 && entry[0] == '/')) { From 94284df7b23dcc8663828c269de23c28ca03fcae Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sun, 12 Oct 2025 00:40:28 +0200 Subject: [PATCH 09/12] Fix GH-20122: getColumnMeta() for JSON-column in MySQL While at it, also add VECTOR. Closes GH-20143. --- NEWS | 1 + .../tests/mysqli_fetch_field_types.phpt | 1 + ext/pdo_mysql/mysql_statement.c | 6 ++++ ext/pdo_mysql/tests/gh20122.phpt | 33 +++++++++++++++++++ 4 files changed, 41 insertions(+) create mode 100644 ext/pdo_mysql/tests/gh20122.phpt diff --git a/NEWS b/NEWS index 265cbcea1140..057d26c7d52e 100644 --- a/NEWS +++ b/NEWS @@ -29,6 +29,7 @@ PHP NEWS - MySQLnd: . Fixed bug GH-8978 (SSL certificate verification fails (port doubled)). (nielsdos) + . Fixed bug GH-20122 (getColumnMeta() for JSON-column in MySQL). (nielsdos) - Opcache: . Fixed bug GH-20081 (access to uninitialized vars in preload_load()). diff --git a/ext/mysqli/tests/mysqli_fetch_field_types.phpt b/ext/mysqli/tests/mysqli_fetch_field_types.phpt index 041eb16694a7..3f58987b3d95 100644 --- a/ext/mysqli/tests/mysqli_fetch_field_types.phpt +++ b/ext/mysqli/tests/mysqli_fetch_field_types.phpt @@ -94,6 +94,7 @@ require_once 'skipifconnectfailure.inc'; MYSQLI_TYPE_NEWDATE => 'MYSQLI_TYPE_NEWDATE - TODO add testing', MYSQLI_TYPE_INTERVAL => 'MYSQLI_TYPE_INTERVAL - TODO add testing', MYSQLI_TYPE_GEOMETRY => 'MYSQLI_TYPE_GEOMETRY - TODO add testing', + MYSQLI_TYPE_JSON => array('JSON', '[]'), ); $datatypes[MYSQLI_TYPE_NEWDECIMAL] = array('DECIMAL', '1.1'); diff --git a/ext/pdo_mysql/mysql_statement.c b/ext/pdo_mysql/mysql_statement.c index c4f86b0e7d32..b3dc527b1091 100644 --- a/ext/pdo_mysql/mysql_statement.c +++ b/ext/pdo_mysql/mysql_statement.c @@ -748,6 +748,12 @@ static char *type_to_name_native(int type) /* {{{ */ PDO_MYSQL_NATIVE_TYPE_NAME(DATE) #ifdef FIELD_TYPE_NEWDATE PDO_MYSQL_NATIVE_TYPE_NAME(NEWDATE) +#endif +#ifdef FIELD_TYPE_VECTOR + PDO_MYSQL_NATIVE_TYPE_NAME(VECTOR) +#endif +#ifdef FIELD_TYPE_JSON + PDO_MYSQL_NATIVE_TYPE_NAME(JSON) #endif PDO_MYSQL_NATIVE_TYPE_NAME(TIME) PDO_MYSQL_NATIVE_TYPE_NAME(DATETIME) diff --git a/ext/pdo_mysql/tests/gh20122.phpt b/ext/pdo_mysql/tests/gh20122.phpt new file mode 100644 index 000000000000..28369fefaf63 --- /dev/null +++ b/ext/pdo_mysql/tests/gh20122.phpt @@ -0,0 +1,33 @@ +--TEST-- +GH-20122 (getColumnMeta() for JSON-column in MySQL) +--EXTENSIONS-- +pdo +pdo_mysql +--SKIPIF-- + +--FILE-- +exec('CREATE TABLE test (bar JSON)'); +$db->exec('INSERT INTO test VALUES("[]")'); + +$stmt = $db->query('SELECT * from test'); +$meta = $stmt->getColumnMeta(0); + +// Note: JSON is an alias for LONGTEXT on MariaDB! +echo $meta['native_type'], "\n"; +?> +--CLEAN-- + +--EXPECTF-- +%r(JSON|LONGTEXT)%r From fbac7a366fc9607e715b53b37bf9287278d79612 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Thu, 16 Oct 2025 23:01:41 +0200 Subject: [PATCH 10/12] phar: Get rid of bailouts in Phar::webPhar() (#20190) Bailouts are bad because they stop the GC etc. They also hide leaks. This makes the behaviour equivalent to exit(), as it's meant to stop the request (which is why bailout was used). We also have to fix some leaks that pop up then. --- ext/phar/phar_object.c | 45 +++++++++++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/ext/phar/phar_object.c b/ext/phar/phar_object.c index 6981d7c026d1..6238e51c7d5c 100644 --- a/ext/phar/phar_object.c +++ b/ext/phar/phar_object.c @@ -699,6 +699,7 @@ PHP_METHOD(Phar, webPhar) zval params, retval; ZVAL_STRINGL(¶ms, entry, entry_len); + efree(entry); rewrite_fci.param_count = 1; rewrite_fci.params = ¶ms; @@ -716,9 +717,10 @@ PHP_METHOD(Phar, webPhar) switch (Z_TYPE(retval)) { case IS_STRING: - efree(entry); + /* TODO: avoid relocation??? */ entry = estrndup(Z_STRVAL_P(rewrite_fci.retval), Z_STRLEN_P(rewrite_fci.retval)); entry_len = Z_STRLEN_P(rewrite_fci.retval); + zval_ptr_dtor_str(&retval); break; case IS_TRUE: case IS_FALSE: @@ -729,15 +731,16 @@ PHP_METHOD(Phar, webPhar) } efree(pt); - zend_bailout(); + zend_throw_unwind_exit(); + return; default: + zval_ptr_dtor(&retval); zend_throw_exception_ex(phar_ce_PharException, 0, "phar error: rewrite callback must return a string or false"); cleanup_fail: if (free_pathinfo) { efree(path_info); } - efree(entry); efree(pt); #ifdef PHP_WIN32 efree(fname); @@ -752,6 +755,10 @@ PHP_METHOD(Phar, webPhar) if (!entry_len || (entry_len == 1 && entry[0] == '/')) { efree(entry); + efree(pt); + + bool is_entry_allocated = false; + /* direct request */ if (index_php_len) { entry = index_php; @@ -759,22 +766,17 @@ PHP_METHOD(Phar, webPhar) if (entry[0] != '/') { spprintf(&entry, 0, "/%s", index_php); ++entry_len; + is_entry_allocated = true; } } else { /* assume "index.php" is starting point */ - entry = estrndup("/index.php", sizeof("/index.php")); + entry = "/index.php"; entry_len = sizeof("/index.php")-1; } if (FAILURE == phar_get_archive(&phar, fname, fname_len, NULL, 0, NULL) || (info = phar_get_entry_info(phar, entry, entry_len, NULL, false)) == NULL) { phar_do_404(phar, fname, fname_len, f404); - - if (free_pathinfo) { - efree(path_info); - } - - zend_bailout(); } else { char *tmp = NULL, sa = '\0'; sapi_header_line ctr = {0}; @@ -801,21 +803,32 @@ PHP_METHOD(Phar, webPhar) *tmp = sa; } - if (free_pathinfo) { - efree(path_info); - } - sapi_header_op(SAPI_HEADER_REPLACE, &ctr); sapi_send_headers(); efree((void *) ctr.line); - zend_bailout(); } + + if (is_entry_allocated) { + efree(entry); + } + if (free_pathinfo) { + efree(path_info); + } + + zend_throw_unwind_exit(); + return; } if (FAILURE == phar_get_archive(&phar, fname, fname_len, NULL, 0, NULL) || (info = phar_get_entry_info(phar, entry, entry_len, NULL, false)) == NULL) { + efree(entry); + efree(pt); + if (free_pathinfo) { + efree(path_info); + } phar_do_404(phar, fname, fname_len, f404); - zend_bailout(); + zend_throw_unwind_exit(); + return; } if (mimeoverride && zend_hash_num_elements(Z_ARRVAL_P(mimeoverride))) { From 1570f6a6b22b19910c3544fa37ef5f9773238ad4 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Thu, 16 Oct 2025 23:54:02 +0200 Subject: [PATCH 11/12] Fix test on 8.4+ --- ext/pdo_mysql/tests/gh20122.phpt | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/ext/pdo_mysql/tests/gh20122.phpt b/ext/pdo_mysql/tests/gh20122.phpt index 28369fefaf63..925c94e907a0 100644 --- a/ext/pdo_mysql/tests/gh20122.phpt +++ b/ext/pdo_mysql/tests/gh20122.phpt @@ -5,15 +5,13 @@ pdo pdo_mysql --SKIPIF-- --FILE-- exec('CREATE TABLE test (bar JSON)'); $db->exec('INSERT INTO test VALUES("[]")'); From 6980d51f52fdaaf926cec5ae8bc17da317f20fbb Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Fri, 17 Oct 2025 00:10:02 +0200 Subject: [PATCH 12/12] [ci skip] Fail test temporarily --- ext/pdo_mysql/tests/gh20122.phpt | 1 + 1 file changed, 1 insertion(+) diff --git a/ext/pdo_mysql/tests/gh20122.phpt b/ext/pdo_mysql/tests/gh20122.phpt index 925c94e907a0..fb3bd70a7e7f 100644 --- a/ext/pdo_mysql/tests/gh20122.phpt +++ b/ext/pdo_mysql/tests/gh20122.phpt @@ -8,6 +8,7 @@ pdo_mysql require_once __DIR__ . '/inc/mysql_pdo_test.inc'; MySQLPDOTest::skip(); ?> +--XFAIL-- --FILE--