diff --git a/.github/matrix.php b/.github/matrix.php index 9164dd4b3c00..64bb60519de6 100644 --- a/.github/matrix.php +++ b/.github/matrix.php @@ -73,7 +73,7 @@ function select_jobs($repository, $trigger, $nightly, $labels, $php_version, $re && ($all_jobs || !$no_jobs || $test_benchmarking) // push trigger is restricted to official repository. && ($repository === 'php/php-src' || $trigger === 'pull_request')) { - $jobs['BENCHMARKING'] = true; + $jobs['BENCHMARKING']['config']['integrated_opcache'] = version_compare($php_version, '8.5', '>='); } if ($all_jobs || $test_community) { $jobs['COMMUNITY']['matrix'] = version_compare($php_version, '8.4', '>=') diff --git a/.github/workflows/test-suite.yml b/.github/workflows/test-suite.yml index 0fd95f67f9c4..9f5496d1d69c 100644 --- a/.github/workflows/test-suite.yml +++ b/.github/workflows/test-suite.yml @@ -1036,6 +1036,7 @@ jobs: sudo mkdir -p /etc/php.d sudo chmod 777 /etc/php.d echo mysqli.default_socket=/var/run/mysqld/mysqld.sock > /etc/php.d/mysqli.ini + ${{ !fromJson(inputs.branch).jobs.BENCHMARKING.config.integrated_opcache && 'echo zend_extension=opcache.so >> /etc/php.d/opcache.ini' || '' }} echo opcache.enable=1 >> /etc/php.d/opcache.ini echo opcache.enable_cli=1 >> /etc/php.d/opcache.ini - name: Setup diff --git a/NEWS b/NEWS index cf36b1bad7c7..4e1196fb0946 100644 --- a/NEWS +++ b/NEWS @@ -37,6 +37,7 @@ PHP NEWS (BogdanUngureanu) . Fixed bug GH-20426 (Spoofchecker::setRestrictionLevel() error message suggests missing constants). (DanielEScherzer) + . Added grapheme_strrev (Yuya Hamada) - JSON: . Enriched JSON last error / exception message with error location. @@ -123,6 +124,8 @@ PHP NEWS defaulted to 0. (Jorg Sowa) . Fixed bug GH-21058 (error_log() crashes with message_type 3 and null destination). (David Carlier) + . Fixed bug GH-13204 (glob() fails if square bracket is in current directory). + (ndossche) - Streams: . Added so_keepalive, tcp_keepidle, tcp_keepintvl and tcp_keepcnt stream diff --git a/UPGRADING b/UPGRADING index 7e47d0ba4817..454a7b900f35 100644 --- a/UPGRADING +++ b/UPGRADING @@ -137,6 +137,10 @@ PHP 8.6 UPGRADE NOTES . Added ReflectionProperty::isReadable() and ReflectionProperty::isWritable(). RFC: https://wiki.php.net/rfc/isreadable-iswriteable +- Intl: + . `grapheme_strrev()` returns strrev for grapheme cluster unit. + RFC: https://wiki.php.net/rfc/grapheme_strrev + - Standard: . `clamp()` returns the given value if in range, else return the nearest bound. diff --git a/UPGRADING.INTERNALS b/UPGRADING.INTERNALS index fc672ac54a82..ccdba855ec52 100644 --- a/UPGRADING.INTERNALS +++ b/UPGRADING.INTERNALS @@ -92,6 +92,14 @@ PHP 8.6 INTERNALS UPGRADE NOTES . Symbol HAVE_ST_BLOCKS has been removed from php_config.h (use HAVE_STRUCT_STAT_ST_BLOCKS). +- Windows build system changes: + . Function SETUP_OPENSSL() doesn't accept 6th argument anymore and doesn't + define the HAVE_OPENSSL_SSL_H preprocessor macro anymore. + . Function SETUP_SQLITE3() doesn't define HAVE_SQLITE3_H and HAVE_SQLITE3EXT_H + preprocessor macros anymore. + . Added a new function CHECK_HEADER() which is intended to be used instead of + the CHECK_HEADER_ADD_INCLUDE(). + ======================== 3. Module changes ======================== diff --git a/ext/bz2/config.w32 b/ext/bz2/config.w32 index afbb8c648cc5..a716320d2ffb 100644 --- a/ext/bz2/config.w32 +++ b/ext/bz2/config.w32 @@ -4,7 +4,7 @@ ARG_WITH("bz2", "BZip2", "no"); if (PHP_BZ2 != "no") { if (CHECK_LIB("libbz2_a.lib;libbz2.lib", "bz2", PHP_BZ2) && - CHECK_HEADER_ADD_INCLUDE("bzlib.h", "CFLAGS_BZ2")) { + CHECK_HEADER("bzlib.h", "CFLAGS_BZ2")) { EXTENSION("bz2", "bz2.c bz2_filter.c"); AC_DEFINE('HAVE_BZ2', 1, "Define to 1 if the PHP extension 'bz2' is available."); // BZ2 extension does this slightly differently from others diff --git a/ext/com_dotnet/config.w32 b/ext/com_dotnet/config.w32 index c4fba4fc539d..0fca82e1dd75 100644 --- a/ext/com_dotnet/config.w32 +++ b/ext/com_dotnet/config.w32 @@ -9,6 +9,10 @@ if (PHP_COM_DOTNET == "yes") { com_typeinfo.c com_variant.c com_wrapper.c com_saproxy.c com_persist.c", null, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1"); AC_DEFINE('HAVE_COM_DOTNET', 1, "Define to 1 if the PHP extension 'com_dotnet' is available."); - CHECK_HEADER_ADD_INCLUDE('mscoree.h', 'CFLAGS_COM_DOTNET'); + + if (CHECK_HEADER('mscoree.h', 'CFLAGS_COM_DOTNET')) { + AC_DEFINE('HAVE_MSCOREE_H', 1, 'Define to 1 if you have the header file.'); + } + ADD_MAKEFILE_FRAGMENT(); } diff --git a/ext/curl/config.w32 b/ext/curl/config.w32 index e097a697eb55..a4bdce59ccb1 100644 --- a/ext/curl/config.w32 +++ b/ext/curl/config.w32 @@ -5,7 +5,7 @@ ARG_WITH("curl", "cURL support", "no"); if (PHP_CURL != "no") { var curl_location; if ((curl_location = CHECK_LIB("libcurl_a.lib;libcurl.lib", "curl", PHP_CURL)) && - CHECK_HEADER_ADD_INCLUDE("curl/easy.h", "CFLAGS_CURL") && + CHECK_HEADER("curl/easy.h", "CFLAGS_CURL") && SETUP_OPENSSL("curl", PHP_CURL) >= 2 && CHECK_LIB("winmm.lib", "curl", PHP_CURL) && CHECK_LIB("wldap32.lib", "curl", PHP_CURL) && diff --git a/ext/dba/config.w32 b/ext/dba/config.w32 index 5017097fe758..0bb9bcc3f4ee 100644 --- a/ext/dba/config.w32 +++ b/ext/dba/config.w32 @@ -15,7 +15,7 @@ if (PHP_DBA != "no") { if (PHP_DB != "no") { if (CHECK_LIB("libdb31s.lib;libdb61.lib", "dba", PHP_DBA) && - CHECK_HEADER_ADD_INCLUDE("db.h", "CFLAGS_DBA")) { + CHECK_HEADER("db.h", "CFLAGS_DBA")) { ADD_FLAG("CFLAGS_DBA", "/D DB1_VERSION=\"\\\"Berkeley DB 1.85 emulation in DB3\\\"\" /D DB1_INCLUDE_FILE=\"\\\"db_185.h\\\"\" /D DBA_DB3=1 /D DB3_INCLUDE_FILE=\"\\\"db.h\\\"\""); } else { WARNING("dba: db handlers not enabled; libraries and headers not found"); @@ -24,7 +24,7 @@ if (PHP_DBA != "no") { if (PHP_QDBM != "no") { if (CHECK_LIB("qdbm_a.lib;qdbm.lib", "dba", PHP_DBA) && - CHECK_HEADER_ADD_INCLUDE("depot.h", "CFLAGS_DBA", PHP_DBA + ";" + PHP_PHP_BUILD + "\\include\\qdbm")) { + CHECK_HEADER("depot.h", "CFLAGS_DBA", PHP_DBA + ";" + PHP_PHP_BUILD + "\\include\\qdbm")) { ADD_SOURCES("ext/dba", "dba_qdbm.c", "dba"); AC_DEFINE("QDBM_INCLUDE_FILE", "", "The QDBM handler header file.", false); AC_DEFINE("DBA_QDBM", 1, "Define to 1 if the dba extension uses the QDBM handler."); @@ -35,7 +35,7 @@ if (PHP_DBA != "no") { if (PHP_LMDB != "no") { if (CHECK_LIB("liblmdb_a.lib", "dba", PHP_DBA) && - CHECK_HEADER_ADD_INCLUDE("lmdb.h", "CFLAGS_DBA") && + CHECK_HEADER("lmdb.h", "CFLAGS_DBA") && CHECK_LIB("ntdll.lib", "dba", PHP_DBA)) { ADD_SOURCES("ext/dba", "dba_lmdb.c", "dba"); AC_DEFINE("LMDB_INCLUDE_FILE", "", "The LMDB handler header file.", false); diff --git a/ext/dom/config.w32 b/ext/dom/config.w32 index 2d8f3f3519c4..e045e29c6bab 100644 --- a/ext/dom/config.w32 +++ b/ext/dom/config.w32 @@ -5,7 +5,7 @@ ARG_WITH("dom", "DOM support", "yes"); if (PHP_DOM == "yes") { if (PHP_LIBXML == "yes" && ADD_EXTENSION_DEP('dom', 'libxml') && - CHECK_HEADER_ADD_INCLUDE("libxml/parser.h", "CFLAGS_DOM", PHP_PHP_BUILD + "\\include\\libxml2") + CHECK_HEADER("libxml/parser.h", "CFLAGS_DOM", PHP_PHP_BUILD + "\\include\\libxml2") ) { EXTENSION("dom", "php_dom.c attr.c document.c infra.c \ xml_document.c html_document.c xml_serializer.c html5_serializer.c html5_parser.c namespace_compat.c private_data.c \ diff --git a/ext/enchant/config.w32 b/ext/enchant/config.w32 index c50f48ffb6c8..45a194cdb7ff 100644 --- a/ext/enchant/config.w32 +++ b/ext/enchant/config.w32 @@ -3,8 +3,8 @@ ARG_WITH("enchant", "Enchant Support", "no"); if (PHP_ENCHANT == "yes") { - if (CHECK_HEADER_ADD_INCLUDE("enchant.h", "CFLAGS_ENCHANT", PHP_ENCHANT+ ";" + PHP_PHP_BUILD + "\\include\\enchant") && - CHECK_HEADER_ADD_INCLUDE("glib.h", "CFLAGS_ENCHANT", PHP_ENCHANT+ ";" + PHP_PHP_BUILD + "\\include\\glib-2.0")) { + if (CHECK_HEADER("enchant.h", "CFLAGS_ENCHANT", PHP_ENCHANT+ ";" + PHP_PHP_BUILD + "\\include\\enchant") && + CHECK_HEADER("glib.h", "CFLAGS_ENCHANT", PHP_ENCHANT+ ";" + PHP_PHP_BUILD + "\\include\\glib-2.0")) { if (CHECK_LIB("libenchant2.lib", "enchant", PHP_ENCHANT)) { have_enchant = true; } else if (CHECK_LIB("libenchant.lib", "enchant", PHP_ENCHANT)) { diff --git a/ext/ffi/config.w32 b/ext/ffi/config.w32 index cfe54706a871..c3d3e7289189 100644 --- a/ext/ffi/config.w32 +++ b/ext/ffi/config.w32 @@ -1,7 +1,7 @@ ARG_WITH('ffi', 'ffi support', 'no'); if (PHP_FFI != 'no') { - if (CHECK_HEADER_ADD_INCLUDE("ffi.h", "CFLAGS_FFI", PHP_FFI+ ";" + PHP_PHP_BUILD + "\\include") && + if (CHECK_HEADER("ffi.h", "CFLAGS_FFI", PHP_FFI+ ";" + PHP_PHP_BUILD + "\\include") && CHECK_LIB("libffi.lib", "ffi", PHP_FFI)) { AC_DEFINE('HAVE_FFI', 1, "Define to 1 if the PHP extension 'ffi' is available."); diff --git a/ext/gd/config.w32 b/ext/gd/config.w32 index a86693ad74be..506bb05cf2e0 100644 --- a/ext/gd/config.w32 +++ b/ext/gd/config.w32 @@ -8,28 +8,29 @@ if (PHP_GD != "no") { if ( CHECK_LIB("libjpeg_a.lib;libjpeg.lib", "gd", PHP_GD) && CHECK_LIB("freetype_a.lib;freetype.lib", "gd", PHP_GD) && - CHECK_HEADER_ADD_INCLUDE("ft2build.h", "CFLAGS_GD", PHP_GD + ";" + PHP_PHP_BUILD + "\\include\\freetype2;" + PHP_PHP_BUILD + "\\include\\freetype") && + CHECK_HEADER("ft2build.h", "CFLAGS_GD", PHP_GD + ";" + PHP_PHP_BUILD + "\\include\\freetype2;" + PHP_PHP_BUILD + "\\include\\freetype") && CHECK_LIB("libpng_a.lib;libpng.lib", "gd", PHP_GD) && - CHECK_HEADER_ADD_INCLUDE("gd.h", "CFLAGS_GD", PHP_GD + ";ext\\gd\\libgd") && - (CHECK_HEADER_ADD_INCLUDE("png.h", "CFLAGS_GD", PHP_GD + ";" + PHP_PHP_BUILD + "\\include\\libpng16") || - CHECK_HEADER_ADD_INCLUDE("png.h", "CFLAGS_GD", PHP_GD + ";" + PHP_PHP_BUILD + "\\include\\libpng15") || - CHECK_HEADER_ADD_INCLUDE("png.h", "CFLAGS_GD", PHP_GD + ";" + PHP_PHP_BUILD + "\\include\\libpng12")) && + CHECK_HEADER("gd.h", "CFLAGS_GD", PHP_GD + ";ext\\gd\\libgd") && + (CHECK_HEADER("png.h", "CFLAGS_GD", PHP_GD + ";" + PHP_PHP_BUILD + "\\include\\libpng16") || + CHECK_HEADER("png.h", "CFLAGS_GD", PHP_GD + ";" + PHP_PHP_BUILD + "\\include\\libpng15") || + CHECK_HEADER("png.h", "CFLAGS_GD", PHP_GD + ";" + PHP_PHP_BUILD + "\\include\\libpng12")) && (CHECK_LIB("libiconv_a.lib;libiconv.lib", "gd", PHP_GD) || CHECK_LIB("iconv_a.lib;iconv.lib", "gd", PHP_GD)) && - CHECK_HEADER_ADD_INCLUDE("iconv.h", "CFLAGS_GD", PHP_GD) && + CHECK_HEADER("iconv.h", "CFLAGS_GD", PHP_GD) && SETUP_ZLIB_LIB("gd", PHP_GD) && - CHECK_HEADER_ADD_INCLUDE("zlib.h", "CFLAGS", "..\\zlib;" + php_usual_include_suspects) + CHECK_HEADER("zlib.h", "CFLAGS", "..\\zlib;" + php_usual_include_suspects) ) { + AC_DEFINE('HAVE_ICONV_H', 1, 'Define to 1 if you have the header'); if (CHECK_LIB("libXpm_a.lib", "gd", PHP_GD) && - CHECK_HEADER_ADD_INCLUDE("xpm.h", "CFLAGS_GD", PHP_GD + ";" + PHP_PHP_BUILD + "\\include\\X11") + CHECK_HEADER("xpm.h", "CFLAGS_GD", PHP_GD + ";" + PHP_PHP_BUILD + "\\include\\X11") ) { AC_DEFINE('HAVE_XPM', 1, "Define to 1 if you have the xpm library."); AC_DEFINE('HAVE_GD_XPM', 1, "Define to 1 if gd extension has XPM support."); } if (PHP_LIBWEBP != "no") { if ((CHECK_LIB("libwebp_a.lib", "gd", PHP_GD) || CHECK_LIB("libwebp.lib", "gd", PHP_GD)) && - CHECK_HEADER_ADD_INCLUDE("decode.h", "CFLAGS_GD", PHP_GD + ";" + PHP_PHP_BUILD + "\\include\\webp") && - CHECK_HEADER_ADD_INCLUDE("encode.h", "CFLAGS_GD", PHP_GD + ";" + PHP_PHP_BUILD + "\\include\\webp")) { + CHECK_HEADER("decode.h", "CFLAGS_GD", PHP_GD + ";" + PHP_PHP_BUILD + "\\include\\webp") && + CHECK_HEADER("encode.h", "CFLAGS_GD", PHP_GD + ";" + PHP_PHP_BUILD + "\\include\\webp")) { AC_DEFINE("HAVE_LIBWEBP", 1, "Define to 1 if you have the libwebp library."); AC_DEFINE("HAVE_GD_WEBP", 1, "Define to 1 if gd extension has WebP support."); } else { @@ -39,10 +40,10 @@ if (PHP_GD != "no") { if (PHP_LIBAVIF != "no") { if (CHECK_LIB("avif_a.lib", "gd", PHP_GD) && CHECK_LIB("aom_a.lib", "gd", PHP_GD) && - CHECK_HEADER_ADD_INCLUDE("avif.h", "CFLAGS_GD", PHP_GD + ";" + PHP_PHP_BUILD + "\\include\\avif")) { + CHECK_HEADER("avif.h", "CFLAGS_GD", PHP_GD + ";" + PHP_PHP_BUILD + "\\include\\avif")) { ADD_FLAG("CFLAGS_GD", "/D HAVE_LIBAVIF /D HAVE_GD_AVIF"); } else if (CHECK_LIB("avif.lib", "gd", PHP_GD) && - CHECK_HEADER_ADD_INCLUDE("avif.h", "CFLAGS_GD", PHP_GD + ";" + PHP_PHP_BUILD + "\\include\\avif")) { + CHECK_HEADER("avif.h", "CFLAGS_GD", PHP_GD + ";" + PHP_PHP_BUILD + "\\include\\avif")) { ADD_FLAG("CFLAGS_GD", "/D HAVE_LIBAVIF /D HAVE_GD_AVIF"); } else { WARNING("libavif not enabled; libraries and headers not found"); diff --git a/ext/gettext/config.w32 b/ext/gettext/config.w32 index 3e644655426b..e4a4168d949b 100644 --- a/ext/gettext/config.w32 +++ b/ext/gettext/config.w32 @@ -3,7 +3,7 @@ ARG_WITH("gettext", "gettext support", "no"); if (PHP_GETTEXT != "no") { - if (CHECK_LIB("libintl_a.lib;libintl.lib", "gettext", PHP_GETTEXT) && CHECK_HEADER_ADD_INCLUDE("libintl.h", "CFLAGS_GETTEXT")) { + if (CHECK_LIB("libintl_a.lib;libintl.lib", "gettext", PHP_GETTEXT) && CHECK_HEADER("libintl.h", "CFLAGS_GETTEXT")) { EXTENSION("gettext", "gettext.c", PHP_GETTEXT_SHARED, "-DHAVE_BIND_TEXTDOMAIN_CODESET=1 -DHAVE_DNGETTEXT=1 -DHAVE_NGETTEXT=1 -DHAVE_LIBINTL=1 -DHAVE_DCNGETTEXT=1"); } else { WARNING("gettext not enabled; libraries and headers not found"); diff --git a/ext/gmp/config.w32 b/ext/gmp/config.w32 index 2bb4aa63ad0f..dc0c1e978d31 100644 --- a/ext/gmp/config.w32 +++ b/ext/gmp/config.w32 @@ -4,7 +4,7 @@ ARG_WITH("gmp", "Include GNU MP support.", "no"); if (PHP_GMP != "no") { if (CHECK_LIB("mpir_a.lib", "gmp", PHP_GMP) && - CHECK_HEADER_ADD_INCLUDE("gmp.h", "CFLAGS_GMP", PHP_GMP + ";" + PHP_PHP_BUILD + "\\include\\mpir")) { + CHECK_HEADER("gmp.h", "CFLAGS_GMP", PHP_GMP + ";" + PHP_PHP_BUILD + "\\include\\mpir")) { EXTENSION("gmp", "gmp.c", null, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1"); PHP_INSTALL_HEADERS("ext/gmp", "php_gmp_int.h"); AC_DEFINE('HAVE_GMP', 1, "Define to 1 if the PHP extension 'gmp' is available."); diff --git a/ext/hash/config.w32 b/ext/hash/config.w32 index dd4c050bcd25..e63efcfd84cb 100644 --- a/ext/hash/config.w32 +++ b/ext/hash/config.w32 @@ -22,7 +22,7 @@ if(X64) { ADD_SOURCES(hash_sha3_dir, 'KeccakHash.c KeccakSponge.c KeccakP-1600-inplace32BI.c', 'hash'); } -if (!CHECK_HEADER_ADD_INCLUDE('KeccakHash.h', 'CFLAGS_HASH', hash_sha3_dir)) { +if (!CHECK_HEADER('KeccakHash.h', 'CFLAGS_HASH', hash_sha3_dir)) { // Should NEVER happen ERROR('Unable to locate SHA3 headers'); } diff --git a/ext/iconv/config.w32 b/ext/iconv/config.w32 index d99c53fb9363..b8fe6804d526 100644 --- a/ext/iconv/config.w32 +++ b/ext/iconv/config.w32 @@ -5,7 +5,7 @@ ARG_WITH("iconv", "iconv support", "yes"); if (PHP_ICONV != "no") { if ((CHECK_LIB("libiconv_a.lib", "iconv", PHP_ICONV) || CHECK_LIB("libiconv.lib", "iconv", PHP_ICONV) || CHECK_LIB("iconv_a.lib", "iconv", PHP_ICONV) || CHECK_LIB("iconv.lib", "iconv", PHP_ICONV)) && - CHECK_HEADER_ADD_INCLUDE("iconv.h", "CFLAGS_ICONV", PHP_ICONV)) { + CHECK_HEADER("iconv.h", "CFLAGS_ICONV", PHP_ICONV)) { EXTENSION("iconv", "iconv.c", PHP_ICONV_SHARED, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1"); diff --git a/ext/intl/config.w32 b/ext/intl/config.w32 index d5c86d123671..da8285b50d0c 100644 --- a/ext/intl/config.w32 +++ b/ext/intl/config.w32 @@ -7,7 +7,7 @@ if (PHP_INTL != "no") { CHECK_LIB("icuin.lib", "intl", PHP_INTL) && CHECK_LIB("icuio.lib", "intl", PHP_INTL) && CHECK_LIB("icuuc.lib", "intl", PHP_INTL) && - CHECK_HEADER_ADD_INCLUDE("unicode/utf.h", "CFLAGS_INTL")) { + CHECK_HEADER("unicode/utf.h", "CFLAGS_INTL")) { // always build as shared - zend_strtod.c/ICU type conflict EXTENSION("intl", "php_intl.c intl_convert.c intl_convertcpp.cpp intl_error.c ", true, "/I \"" + configure_module_dirname + "\" /DZEND_ENABLE_STATIC_TSRMLS_CACHE=1"); @@ -92,7 +92,7 @@ if (PHP_INTL != "no") { resourcebundle_iterator.cpp", "intl"); - if (CHECK_HEADER_ADD_INCLUDE("unicode/uspoof.h", "CFLAGS_INTL")) { + if (CHECK_HEADER("unicode/uspoof.h", "CFLAGS_INTL")) { ADD_SOURCES(configure_module_dirname + "/spoofchecker", "\ spoofchecker_class.cpp \ spoofchecker_create.cpp \ diff --git a/ext/intl/grapheme/grapheme_string.cpp b/ext/intl/grapheme/grapheme_string.cpp index 6dd5a002a65b..36c0cc0f732c 100644 --- a/ext/intl/grapheme/grapheme_string.cpp +++ b/ext/intl/grapheme/grapheme_string.cpp @@ -1135,4 +1135,63 @@ U_CFUNC PHP_FUNCTION(grapheme_levenshtein) efree(ustring1); } +U_CFUNC PHP_FUNCTION(grapheme_strrev) +{ + zend_string *string; + UText *ut = nullptr; + UErrorCode ustatus = U_ZERO_ERROR; + UBreakIterator *bi; + char *pstr, *end, *p; + zend_string *ret; + int32_t pos = 0, current = 0, end_len = 0; + unsigned char u_break_iterator_buffer[U_BRK_SAFECLONE_BUFFERSIZE]; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_STR(string) + ZEND_PARSE_PARAMETERS_END(); + + if (ZSTR_LEN(string) == 0) { + RETURN_EMPTY_STRING(); + } + + pstr = ZSTR_VAL(string); + ut = utext_openUTF8(ut, pstr, ZSTR_LEN(string), &ustatus); + + if (U_FAILURE(ustatus)) { + intl_error_set_code(nullptr, ustatus); + intl_error_set_custom_msg(nullptr, "Error opening UTF-8 text"); + + RETVAL_FALSE; + goto close; + } + + bi = nullptr; + ustatus = U_ZERO_ERROR; + + bi = grapheme_get_break_iterator((void*)u_break_iterator_buffer, &ustatus ); + ret = zend_string_alloc(ZSTR_LEN(string), 0); + p = ZSTR_VAL(ret); + + ubrk_setUText(bi, ut, &ustatus); + pos = ubrk_last(bi); + if (pos == UBRK_DONE) { + goto ubrk_end; + } + + current = ZSTR_LEN(string); + for (end = pstr; pos != UBRK_DONE; ) { + pos = ubrk_previous(bi); + end_len = current - pos; + for (int32_t j = 0; j < end_len; j++) { + *p++ = *(pstr + pos + j); + } + current = pos; + } +ubrk_end: + RETVAL_NEW_STR(ret); + ubrk_close(bi); +close: + utext_close(ut); +} + /* }}} */ diff --git a/ext/intl/php_intl.stub.php b/ext/intl/php_intl.stub.php index 9a8f036865cd..4bcb8587f786 100644 --- a/ext/intl/php_intl.stub.php +++ b/ext/intl/php_intl.stub.php @@ -445,6 +445,8 @@ function grapheme_str_split(string $string, int $length = 1): array|false {} function grapheme_levenshtein(string $string1, string $string2, int $insertion_cost = 1, int $replacement_cost = 1, int $deletion_cost = 1, string $locale = ""): int|false {} +function grapheme_strrev(string $string): string|false {} + /** @param int $next */ function grapheme_extract(string $haystack, int $size, int $type = GRAPHEME_EXTR_COUNT, int $offset = 0, &$next = null): string|false {} diff --git a/ext/intl/php_intl_arginfo.h b/ext/intl/php_intl_arginfo.h index e00e51420d46..81160349980c 100644 --- a/ext/intl/php_intl_arginfo.h +++ b/ext/intl/php_intl_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit php_intl.stub.php instead. - * Stub hash: d9e331c3a1ae46f8eae07ef0d39cb9990e74a0d1 */ + * Stub hash: c52fd0def2530be628beedbbcdcfecdcb07449a8 */ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_intlcal_create_instance, 0, 0, IntlCalendar, 1) ZEND_ARG_OBJ_TYPE_MASK(0, timezone, IntlTimeZone|DateTimeZone, MAY_BE_STRING|MAY_BE_NULL, "null") @@ -501,6 +501,10 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_grapheme_levenshtein, 0, 2, MAY_ ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, locale, IS_STRING, 0, "\"\"") ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_grapheme_strrev, 0, 1, MAY_BE_STRING|MAY_BE_FALSE) + ZEND_ARG_TYPE_INFO(0, string, IS_STRING, 0) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_grapheme_extract, 0, 2, MAY_BE_STRING|MAY_BE_FALSE) ZEND_ARG_TYPE_INFO(0, haystack, IS_STRING, 0) ZEND_ARG_TYPE_INFO(0, size, IS_LONG, 0) @@ -922,6 +926,7 @@ ZEND_FUNCTION(grapheme_strstr); ZEND_FUNCTION(grapheme_stristr); ZEND_FUNCTION(grapheme_str_split); ZEND_FUNCTION(grapheme_levenshtein); +ZEND_FUNCTION(grapheme_strrev); ZEND_FUNCTION(grapheme_extract); ZEND_FUNCTION(idn_to_ascii); ZEND_FUNCTION(idn_to_utf8); @@ -1113,6 +1118,7 @@ static const zend_function_entry ext_functions[] = { ZEND_FE(grapheme_stristr, arginfo_grapheme_stristr) ZEND_FE(grapheme_str_split, arginfo_grapheme_str_split) ZEND_FE(grapheme_levenshtein, arginfo_grapheme_levenshtein) + ZEND_FE(grapheme_strrev, arginfo_grapheme_strrev) ZEND_FE(grapheme_extract, arginfo_grapheme_extract) ZEND_FE(idn_to_ascii, arginfo_idn_to_ascii) ZEND_FE(idn_to_utf8, arginfo_idn_to_utf8) diff --git a/ext/intl/tests/grapheme_strrev.phpt b/ext/intl/tests/grapheme_strrev.phpt new file mode 100644 index 000000000000..dff84fbba8e9 Binary files /dev/null and b/ext/intl/tests/grapheme_strrev.phpt differ diff --git a/ext/ldap/config.w32 b/ext/ldap/config.w32 index f9bc8662ac50..7dbb353dd80b 100644 --- a/ext/ldap/config.w32 +++ b/ext/ldap/config.w32 @@ -4,8 +4,8 @@ ARG_WITH("ldap", "LDAP support", "no"); if (PHP_LDAP != "no") { - if (CHECK_HEADER_ADD_INCLUDE("ldap.h", "CFLAGS_LDAP", PHP_PHP_BUILD + "\\include\\openldap;" + PHP_PHP_BUILD + "\\openldap\\include;" + PHP_LDAP) && - CHECK_HEADER_ADD_INCLUDE("lber.h", "CFLAGS_LDAP", PHP_PHP_BUILD + "\\include\\openldap;" + PHP_PHP_BUILD + "\\openldap\\include;" + PHP_LDAP) && + if (CHECK_HEADER("ldap.h", "CFLAGS_LDAP", PHP_PHP_BUILD + "\\include\\openldap;" + PHP_PHP_BUILD + "\\openldap\\include;" + PHP_LDAP) && + CHECK_HEADER("lber.h", "CFLAGS_LDAP", PHP_PHP_BUILD + "\\include\\openldap;" + PHP_PHP_BUILD + "\\openldap\\include;" + PHP_LDAP) && SETUP_OPENSSL("ldap", PHP_LDAP) >= 2 && CHECK_LIB("oldap32_a.lib", "ldap", PHP_LDAP) && CHECK_LIB("olber32_a.lib", "ldap", PHP_LDAP)&& diff --git a/ext/libxml/config.w32 b/ext/libxml/config.w32 index 2362ea0c2ba3..072dd691f214 100644 --- a/ext/libxml/config.w32 +++ b/ext/libxml/config.w32 @@ -5,8 +5,8 @@ ARG_WITH("libxml", "LibXML support", "yes"); if (PHP_LIBXML == "yes") { if (CHECK_LIB("libxml2_a_dll.lib;libxml2_a.lib", "libxml") && ((PHP_ICONV != "no" && !PHP_ICONV_SHARED) || CHECK_LIB("libiconv_a.lib;iconv_a.lib;libiconv.lib;iconv.lib", "libxml")) && - CHECK_HEADER_ADD_INCLUDE("libxml/parser.h", "CFLAGS_LIBXML", PHP_PHP_BUILD + "\\include\\libxml2") && - CHECK_HEADER_ADD_INCLUDE("libxml/tree.h", "CFLAGS_LIBXML", PHP_PHP_BUILD + "\\include\\libxml2")) { + CHECK_HEADER("libxml/parser.h", "CFLAGS_LIBXML", PHP_PHP_BUILD + "\\include\\libxml2") && + CHECK_HEADER("libxml/tree.h", "CFLAGS_LIBXML", PHP_PHP_BUILD + "\\include\\libxml2")) { if (GREP_HEADER("libxml/xmlversion.h", "#define\\s+LIBXML_VERSION\\s+(\\d+)", PHP_PHP_BUILD + "\\include\\libxml2") && +RegExp.$1 >= 20904) { diff --git a/ext/mbstring/config.w32 b/ext/mbstring/config.w32 index 070d3d73137a..7874da85a25d 100644 --- a/ext/mbstring/config.w32 +++ b/ext/mbstring/config.w32 @@ -5,7 +5,7 @@ ARG_ENABLE("mbregex", "multibyte regex support", "no"); if (PHP_MBSTRING != "no") { - if (CHECK_HEADER_ADD_INCLUDE("mbstring.h", "CFLAGS_MBSTRING", PHP_MBSTRING + ";" + PHP_PHP_BUILD + "\\include")) { + if (CHECK_HEADER("mbstring.h", "CFLAGS_MBSTRING", PHP_MBSTRING + ";" + PHP_PHP_BUILD + "\\include")) { EXTENSION("mbstring", "mbstring.c php_unicode.c mb_gpc.c", PHP_MBSTRING_SHARED); ADD_EXTENSION_DEP('mbstring', 'pcre'); @@ -42,7 +42,7 @@ if (PHP_MBSTRING != "no") { AC_DEFINE('HAVE_MBSTRING', 1, "Define to 1 if the PHP extension 'mbstring' is available."); if (PHP_MBREGEX != "no") { - if (CHECK_HEADER_ADD_INCLUDE("oniguruma.h", "CFLAGS_MBSTRING", PHP_MBREGEX) && + if (CHECK_HEADER("oniguruma.h", "CFLAGS_MBSTRING", PHP_MBREGEX) && CHECK_LIB("onig_a.lib;libonig_a.lib", "mbstring", PHP_MBSTRING)) { AC_DEFINE('HAVE_MBREGEX', 1, 'Define to 1 if mbstring has multibyte regex support enabled.'); diff --git a/ext/mysqlnd/config.w32 b/ext/mysqlnd/config.w32 index cf6bf4b61ccc..e88b269c4863 100644 --- a/ext/mysqlnd/config.w32 +++ b/ext/mysqlnd/config.w32 @@ -29,7 +29,7 @@ if (PHP_MYSQLND != "no") { "php_mysqlnd.c "; EXTENSION("mysqlnd", mysqlnd_source, false, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1"); if (SETUP_ZLIB_LIB("mysqlnd", PHP_MYSQLND) && - CHECK_HEADER_ADD_INCLUDE("zlib.h", "CFLAGS", "..\\zlib;" + php_usual_include_suspects) + CHECK_HEADER("zlib.h", "CFLAGS", "..\\zlib;" + php_usual_include_suspects) ) { AC_DEFINE("MYSQLND_COMPRESSION_ENABLED", 1, "Define to 1 if mysqlnd has compressed protocol support."); AC_DEFINE("MYSQLND_SSL_SUPPORTED", 1, "Define to 1 if mysqlnd core SSL is enabled."); diff --git a/ext/odbc/config.w32 b/ext/odbc/config.w32 index 7afa9ce8b649..242cc5992d46 100644 --- a/ext/odbc/config.w32 +++ b/ext/odbc/config.w32 @@ -4,8 +4,8 @@ ARG_ENABLE("odbc", "ODBC support", "no"); if (PHP_ODBC == "yes") { if (CHECK_LIB("odbc32.lib", "odbc") && CHECK_LIB("odbccp32.lib", "odbc") - && CHECK_HEADER_ADD_INCLUDE("sql.h", "CFLAGS_ODBC") - && CHECK_HEADER_ADD_INCLUDE("sqlext.h", "CFLAGS_ODBC")) { + && CHECK_HEADER("sql.h", "CFLAGS_ODBC") + && CHECK_HEADER("sqlext.h", "CFLAGS_ODBC")) { EXTENSION("odbc", "php_odbc.c odbc_utils.c", PHP_ODBC_SHARED, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1"); AC_DEFINE("HAVE_UODBC", 1, "Define to 1 if the PHP extension 'odbc' is available."); } else { diff --git a/ext/opcache/config.w32 b/ext/opcache/config.w32 index 9b8f2a7e5107..397fa1bdd87d 100644 --- a/ext/opcache/config.w32 +++ b/ext/opcache/config.w32 @@ -23,7 +23,7 @@ ADD_EXTENSION_DEP('opcache', 'pcre'); if (PHP_OPCACHE_JIT == "yes") { if (TARGET_ARCH == 'arm64') { WARNING("JIT not enabled; not yet supported for ARM64"); - } else if (CHECK_HEADER_ADD_INCLUDE("ir/ir.h", "CFLAGS_OPCACHE", PHP_OPCACHE + ";ext\\opcache\\jit")) { + } else if (CHECK_HEADER("ir/ir.h", "CFLAGS_OPCACHE", PHP_OPCACHE + ";ext\\opcache\\jit")) { var dasm_flags = (X64 ? "-D X64=1" : "") + (X64 ? " -D X64WIN=1" : "") + " -D WIN=1"; var ir_target = (X64 ? "IR_TARGET_X64" : "IR_TARGET_X86"); var ir_src = "ir_strtab.c ir_cfg.c ir_sccp.c ir_gcm.c ir_ra.c ir_save.c \ @@ -41,7 +41,7 @@ if (PHP_OPCACHE_JIT == "yes") { ADD_FLAG("CFLAGS_OPCACHE", "/D IR_DEBUG"); } - if (CHECK_HEADER_ADD_INCLUDE("capstone\\capstone.h", "CFLAGS_OPCACHE", PHP_OPCACHE+ ";" + PHP_PHP_BUILD + "\\include") && + if (CHECK_HEADER("capstone\\capstone.h", "CFLAGS_OPCACHE", PHP_OPCACHE+ ";" + PHP_PHP_BUILD + "\\include") && CHECK_LIB("capstone.lib", "opcache", PHP_OPCACHE)) { AC_DEFINE('HAVE_CAPSTONE', 1, 'Define to 1 if Capstone is available.'); ir_src += " ir_disasm.c"; diff --git a/ext/pdo_dblib/config.w32 b/ext/pdo_dblib/config.w32 index 4b1c76130f52..07e98d16a4af 100644 --- a/ext/pdo_dblib/config.w32 +++ b/ext/pdo_dblib/config.w32 @@ -7,7 +7,7 @@ if (PHP_PDO_DBLIB != "no") { * otherwise we'll poke around and look for MSSQL libs */ if (CHECK_LIB("sybdb.lib", "pdo_dblib", PHP_PDO_DBLIB) && - CHECK_HEADER_ADD_INCLUDE("sybfront.h", "CFLAGS_PDO_DBLIB", + CHECK_HEADER("sybfront.h", "CFLAGS_PDO_DBLIB", PHP_PDO_DBLIB, null, null, true)) { EXTENSION("pdo_dblib", "pdo_dblib.c dblib_driver.c dblib_stmt.c", null, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1"); @@ -24,7 +24,7 @@ if (PHP_PDO_MSSQL != "no") { PDO_DBLIB_FLAVOUR = 0; if (CHECK_LIB("sybdb.lib", "pdo_mssql", PHP_PDO_MSSQL) && - CHECK_HEADER_ADD_INCLUDE("sybfront.h", "CFLAGS_PDO_MSSQL", + CHECK_HEADER("sybfront.h", "CFLAGS_PDO_MSSQL", PHP_PDO_MSSQL, null, null, true)) { /* smells like FreeTDS (or maybe native sybase dblib) */ PDO_DBLIB_FLAVOUR = "freetds"; diff --git a/ext/pdo_firebird/config.w32 b/ext/pdo_firebird/config.w32 index 003a1a677082..1c5cb4214ad7 100644 --- a/ext/pdo_firebird/config.w32 +++ b/ext/pdo_firebird/config.w32 @@ -5,9 +5,9 @@ ARG_WITH("pdo-firebird", "Firebird support for PDO", "no"); if (PHP_PDO_FIREBIRD != "no") { if (CHECK_LIB("fbclient_ms.lib", "pdo_firebird", PHP_PHP_BUILD + "\\interbase\\lib_ms;" + PHP_PDO_FIREBIRD) - && CHECK_HEADER_ADD_INCLUDE("ibase.h", "CFLAGS_PDO_FIREBIRD", + && CHECK_HEADER("ibase.h", "CFLAGS_PDO_FIREBIRD", PHP_PHP_BUILD + "\\include\\interbase;" + PHP_PHP_BUILD + "\\interbase\\include;" + PHP_PDO_FIREBIRD) - && CHECK_HEADER_ADD_INCLUDE("firebird\\Interface.h", "CFLAGS_PDO_FIREBIRD", + && CHECK_HEADER("firebird\\Interface.h", "CFLAGS_PDO_FIREBIRD", PHP_PHP_BUILD + "\\include\\interbase;" + PHP_PHP_BUILD + "\\interbase\\include;" + PHP_PDO_FIREBIRD) ) { diff --git a/ext/pdo_mysql/config.w32 b/ext/pdo_mysql/config.w32 index ece466975c55..95899d2270c8 100644 --- a/ext/pdo_mysql/config.w32 +++ b/ext/pdo_mysql/config.w32 @@ -12,7 +12,7 @@ if (PHP_PDO_MYSQL != "no") { ADD_MAKEFILE_FRAGMENT(); } else { if (CHECK_LIB("libmysql.lib", "pdo_mysql", PHP_PDO_MYSQL) && - CHECK_HEADER_ADD_INCLUDE("mysql.h", "CFLAGS_PDO_MYSQL", + CHECK_HEADER("mysql.h", "CFLAGS_PDO_MYSQL", PHP_PDO_MYSQL + "\\include;" + PHP_PHP_BUILD + "\\include\\mysql;" + PHP_PDO_MYSQL)) { diff --git a/ext/pdo_odbc/config.w32 b/ext/pdo_odbc/config.w32 index 6a94da7f7953..e70516195718 100644 --- a/ext/pdo_odbc/config.w32 +++ b/ext/pdo_odbc/config.w32 @@ -4,11 +4,13 @@ ARG_WITH("pdo-odbc", "ODBC support for PDO", "no"); if (PHP_PDO_ODBC != "no") { if (CHECK_LIB("odbc32.lib", "pdo_odbc") && CHECK_LIB("odbccp32.lib", "pdo_odbc") - && CHECK_HEADER_ADD_INCLUDE('sql.h', 'CFLAGS_PDO_ODBC') - && CHECK_HEADER_ADD_INCLUDE('sqlext.h', 'CFLAGS_PDO_ODBC')) { + && CHECK_HEADER('sql.h', 'CFLAGS_PDO_ODBC') + && CHECK_HEADER('sqlext.h', 'CFLAGS_PDO_ODBC')) { EXTENSION("pdo_odbc", "pdo_odbc.c odbc_driver.c odbc_stmt.c"); ADD_EXTENSION_DEP('pdo_odbc', 'pdo'); + AC_DEFINE('HAVE_SQL_H', 1, 'Define to 1 if you have the header.'); + AC_DEFINE('HAVE_SQLEXT_H', 1, 'Define to 1 if you have the header.'); } else { WARNING("pdo_odbc support can't be enabled, headers or libraries are missing (SDK)") diff --git a/ext/pdo_pgsql/config.w32 b/ext/pdo_pgsql/config.w32 index aec5db508d07..5fc25f215900 100644 --- a/ext/pdo_pgsql/config.w32 +++ b/ext/pdo_pgsql/config.w32 @@ -4,7 +4,7 @@ ARG_WITH("pdo-pgsql", "PostgreSQL support for PDO", "no"); if (PHP_PDO_PGSQL != "no") { if (CHECK_LIB("libpq.lib", "pdo_pgsql", PHP_PDO_PGSQL) && - CHECK_HEADER_ADD_INCLUDE("libpq-fe.h", "CFLAGS_PDO_PGSQL", PHP_PDO_PGSQL + "\\include;" + PHP_PHP_BUILD + "\\include\\pgsql;" + PHP_PHP_BUILD + "\\include\\libpq;")) { + CHECK_HEADER("libpq-fe.h", "CFLAGS_PDO_PGSQL", PHP_PDO_PGSQL + "\\include;" + PHP_PHP_BUILD + "\\include\\pgsql;" + PHP_PHP_BUILD + "\\include\\libpq;")) { EXTENSION("pdo_pgsql", "pdo_pgsql.c pgsql_driver.c pgsql_statement.c pgsql_sql_parser.c"); AC_DEFINE('HAVE_PDO_PGSQL', 1, "Define to 1 if the PHP extension 'pdo_pgsql' is available."); diff --git a/ext/pgsql/config.w32 b/ext/pgsql/config.w32 index 3ca5fc2f1691..14eb5a07a0e9 100644 --- a/ext/pgsql/config.w32 +++ b/ext/pgsql/config.w32 @@ -4,7 +4,7 @@ ARG_WITH("pgsql", "PostgreSQL support", "no"); if (PHP_PGSQL != "no") { if (CHECK_LIB("libpq.lib", "pgsql", PHP_PGSQL) && - CHECK_HEADER_ADD_INCLUDE("libpq-fe.h", "CFLAGS_PGSQL", PHP_PGSQL + "\\include;" + PHP_PHP_BUILD + "\\include\\pgsql;" + PHP_PHP_BUILD + "\\include\\libpq;" + PHP_PGSQL)) { + CHECK_HEADER("libpq-fe.h", "CFLAGS_PGSQL", PHP_PGSQL + "\\include;" + PHP_PHP_BUILD + "\\include\\pgsql;" + PHP_PHP_BUILD + "\\include\\libpq;" + PHP_PGSQL)) { EXTENSION("pgsql", "pgsql.c", PHP_PGSQL_SHARED, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1"); AC_DEFINE('HAVE_PGSQL', 1, "Define to 1 if the PHP extension 'pgsql' is available."); ADD_FLAG("CFLAGS_PGSQL", "/D PGSQL_EXPORTS"); diff --git a/ext/readline/config.w32 b/ext/readline/config.w32 index 8f3a2db61f23..2ff9cc8a2bbc 100644 --- a/ext/readline/config.w32 +++ b/ext/readline/config.w32 @@ -4,7 +4,7 @@ ARG_WITH("readline", "Readline support", "yes"); if (PHP_READLINE != "no") { if (CHECK_LIB("edit_a.lib;edit.lib", "readline", PHP_READLINE) && - CHECK_HEADER_ADD_INCLUDE("editline/readline.h", "CFLAGS_READLINE")) { + CHECK_HEADER("editline/readline.h", "CFLAGS_READLINE")) { EXTENSION("readline", "readline.c readline_cli.c"); ADD_FLAG("CFLAGS_READLINE", "/D HAVE_LIBEDIT"); ADD_FLAG("CFLAGS_READLINE", "/D HAVE_RL_COMPLETION_MATCHES"); diff --git a/ext/simplexml/config.w32 b/ext/simplexml/config.w32 index 8942e6c93e3b..0c2e7c5f5a79 100644 --- a/ext/simplexml/config.w32 +++ b/ext/simplexml/config.w32 @@ -6,7 +6,7 @@ if (PHP_SIMPLEXML == "yes") { if(PHP_LIBXML == "yes" && ADD_EXTENSION_DEP('simplexml', 'libxml') && ADD_EXTENSION_DEP('simplexml', 'spl') && - CHECK_HEADER_ADD_INCLUDE("libxml/tree.h", "CFLAGS_SIMPLEXML", PHP_PHP_BUILD + "\\include\\libxml2") + CHECK_HEADER("libxml/tree.h", "CFLAGS_SIMPLEXML", PHP_PHP_BUILD + "\\include\\libxml2") ) { EXTENSION("simplexml", "simplexml.c"); AC_DEFINE("HAVE_SIMPLEXML", 1, "Define to 1 if the PHP extension 'simplexml' is available."); diff --git a/ext/snmp/config.w32 b/ext/snmp/config.w32 index a2facb6946d6..0e3887c0de68 100644 --- a/ext/snmp/config.w32 +++ b/ext/snmp/config.w32 @@ -3,7 +3,7 @@ ARG_WITH("snmp", "SNMP support", "no"); if (PHP_SNMP != "no") { - if (CHECK_HEADER_ADD_INCLUDE("snmp.h", "CFLAGS_SNMP", PHP_PHP_BUILD + "\\include\\net-snmp;" + PHP_SNMP) && + if (CHECK_HEADER("snmp.h", "CFLAGS_SNMP", PHP_PHP_BUILD + "\\include\\net-snmp;" + PHP_SNMP) && SETUP_OPENSSL("snmp", PHP_SNMP) >= 2) { if (CHECK_LIB("netsnmp.lib", "snmp", PHP_SNMP)) { EXTENSION('snmp', 'snmp.c'); diff --git a/ext/soap/config.w32 b/ext/soap/config.w32 index 583f6a2b2e0d..7cecb8e8afed 100644 --- a/ext/soap/config.w32 +++ b/ext/soap/config.w32 @@ -5,8 +5,8 @@ ARG_ENABLE("soap", "SOAP support", "no"); if (PHP_SOAP != "no") { if (PHP_LIBXML == "yes" && ADD_EXTENSION_DEP('soap', 'libxml') && - CHECK_HEADER_ADD_INCLUDE("libxml/parser.h", "CFLAGS_SOAP", PHP_PHP_BUILD + "\\include\\libxml2") && - CHECK_HEADER_ADD_INCLUDE("libxml/tree.h", "CFLAGS_SOAP", PHP_PHP_BUILD + "\\include\\libxml2") + CHECK_HEADER("libxml/parser.h", "CFLAGS_SOAP", PHP_PHP_BUILD + "\\include\\libxml2") && + CHECK_HEADER("libxml/tree.h", "CFLAGS_SOAP", PHP_PHP_BUILD + "\\include\\libxml2") ) { EXTENSION('soap', 'soap.c php_encoding.c php_http.c php_packet_soap.c php_schema.c php_sdl.c php_xml.c', null, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1"); AC_DEFINE('HAVE_SOAP', 1, "Define to 1 if the PHP extension 'soap' is available."); diff --git a/ext/sodium/config.w32 b/ext/sodium/config.w32 index bde640629460..19c548898ab9 100644 --- a/ext/sodium/config.w32 +++ b/ext/sodium/config.w32 @@ -3,7 +3,7 @@ ARG_WITH("sodium", "for libsodium support", "no"); if (PHP_SODIUM != "no") { - if (CHECK_LIB("libsodium.lib", "sodium", PHP_SODIUM) && CHECK_HEADER_ADD_INCLUDE("sodium.h", "CFLAGS_SODIUM")) { + if (CHECK_LIB("libsodium.lib", "sodium", PHP_SODIUM) && CHECK_HEADER("sodium.h", "CFLAGS_SODIUM")) { EXTENSION("sodium", "libsodium.c sodium_pwhash.c"); AC_DEFINE('HAVE_LIBSODIUMLIB', 1 , "Define to 1 if the PHP extension 'sodium' is available."); PHP_INSTALL_HEADERS("ext/sodium", "php_libsodium.h"); diff --git a/ext/standard/config.w32 b/ext/standard/config.w32 index c7c14b8705ca..bb88e0931d24 100644 --- a/ext/standard/config.w32 +++ b/ext/standard/config.w32 @@ -4,7 +4,7 @@ ARG_WITH("password-argon2", "Argon2 support", "no"); if (PHP_PASSWORD_ARGON2 != "no") { if (CHECK_LIB("argon2_a.lib;argon2.lib", null, PHP_PASSWORD_ARGON2) - && CHECK_HEADER_ADD_INCLUDE("argon2.h", "CFLAGS")) { + && CHECK_HEADER("argon2.h", "CFLAGS")) { if (!CHECK_FUNC_IN_HEADER("argon2.h", "argon2id_hash_raw", PHP_PHP_BUILD + "\\include", "CFLAGS")) { ERROR("Please verify that Argon2 header and libraries >= 20161029 are installed"); } @@ -19,7 +19,7 @@ ARG_WITH("config-file-scan-dir", "Dir to check for additional php ini files", "" AC_DEFINE("PHP_CONFIG_FILE_SCAN_DIR", PHP_CONFIG_FILE_SCAN_DIR); AC_DEFINE("PHP_USE_PHP_CRYPT_R", 1, "Define to 1 if PHP uses its own crypt_r, and to 0 if using the external crypt library."); -CHECK_HEADER_ADD_INCLUDE("timelib_config.h", "CFLAGS_STANDARD", "ext/date/lib"); +CHECK_HEADER("timelib_config.h", "CFLAGS_STANDARD", "ext/date/lib"); ADD_FLAG("LIBS_STANDARD", "iphlpapi.lib"); diff --git a/ext/standard/dir.c b/ext/standard/dir.c index 7c1f8efe6887..730ef6154907 100644 --- a/ext/standard/dir.c +++ b/ext/standard/dir.c @@ -400,13 +400,34 @@ PHP_FUNCTION(getcwd) /* }}} */ /* {{{ Find pathnames matching a pattern */ +#if defined(ZTS) && defined(PHP_GLOB_ALTDIRFUNC) +static void *php_glob_opendir_wrapper(const char *path) +{ + return VCWD_OPENDIR(path); +} + +static void php_glob_closedir_wrapper(void *dir) +{ + (void) closedir(dir); +} + +static int php_glob_lstat_wrapper(const char *buf, zend_stat_t *sb) +{ + return VCWD_LSTAT(buf, sb); +} + +static int php_glob_stat_wrapper(const char *buf, zend_stat_t *sb) +{ + return VCWD_STAT(buf, sb); +} +#endif + PHP_FUNCTION(glob) { size_t cwd_skip = 0; -#ifdef ZTS +#if defined(ZTS) && !defined(PHP_GLOB_ALTDIRFUNC) char cwd[MAXPATHLEN]; char work_pattern[MAXPATHLEN]; - char *result; #endif char *pattern = NULL; size_t pattern_len; @@ -433,28 +454,45 @@ PHP_FUNCTION(glob) RETURN_FALSE; } + memset(&globbuf, 0, sizeof(globbuf)); + + int passed_glob_flags = flags & PHP_GLOB_FLAGMASK; + #ifdef ZTS if (!IS_ABSOLUTE_PATH(pattern, pattern_len)) { - result = VCWD_GETCWD(cwd, MAXPATHLEN); + /* System glob uses the current work directory which is not thread safe. + * The first fix is to override the functions used to open/read/... paths + * with the VCWD ones used in PHP. + * If that functionality is unavailable for whatever reason, fall back + * to prepending the current working directory to the passed path. + * However, that comes with limitations regarding meta characters + * that is not solvable in general (GH-13204). */ +# ifdef PHP_GLOB_ALTDIRFUNC + globbuf.gl_opendir = php_glob_opendir_wrapper; + globbuf.gl_readdir = (struct dirent *(*)(void *)) readdir; + globbuf.gl_closedir = php_glob_closedir_wrapper; + globbuf.gl_lstat = php_glob_lstat_wrapper; + globbuf.gl_stat = php_glob_stat_wrapper; + passed_glob_flags |= PHP_GLOB_ALTDIRFUNC; +# else + char *result = VCWD_GETCWD(cwd, MAXPATHLEN); if (!result) { cwd[0] = '\0'; } -#ifdef PHP_WIN32 +# ifdef PHP_WIN32 if (IS_SLASH(*pattern)) { cwd[2] = '\0'; } -#endif +# endif cwd_skip = strlen(cwd)+1; snprintf(work_pattern, MAXPATHLEN, "%s%c%s", cwd, DEFAULT_SLASH, pattern); pattern = work_pattern; +# endif } #endif - - memset(&globbuf, 0, sizeof(globbuf)); - globbuf.gl_offs = 0; - if (0 != (ret = php_glob(pattern, flags & PHP_GLOB_FLAGMASK, NULL, &globbuf))) { + if (0 != (ret = php_glob(pattern, passed_glob_flags, NULL, &globbuf))) { #ifdef PHP_GLOB_NOMATCH if (PHP_GLOB_NOMATCH == ret) { /* Some glob implementation simply return no data if no matches diff --git a/ext/standard/tests/file/gh13204.phpt b/ext/standard/tests/file/gh13204.phpt new file mode 100644 index 000000000000..1af66539195a --- /dev/null +++ b/ext/standard/tests/file/gh13204.phpt @@ -0,0 +1,12 @@ +--TEST-- +GH-13204 (glob() fails if square bracket is in current directory) +--FILE-- + +--EXPECT-- +array(1) { + [0]=> + string(11) "./empty.txt" +} diff --git a/ext/standard/tests/file/gh13204[brackets]/empty.txt b/ext/standard/tests/file/gh13204[brackets]/empty.txt new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/ext/tidy/config.w32 b/ext/tidy/config.w32 index 1b2436ac9dfa..8cbb5b9e681c 100644 --- a/ext/tidy/config.w32 +++ b/ext/tidy/config.w32 @@ -7,12 +7,12 @@ if (PHP_TIDY != "no") { if ((CHECK_LIB("libtidy_a.lib;tidy_a.lib", "tidy", PHP_TIDY) && (tidy_static = true) || CHECK_LIB("libtidy.lib;tidy.lib", "tidy", PHP_TIDY)) && ( - CHECK_HEADER_ADD_INCLUDE("tidy.h", "CFLAGS_TIDY") || - CHECK_HEADER_ADD_INCLUDE("tidy/tidy.h", "CFLAGS_TIDY", null, null, true) || - CHECK_HEADER_ADD_INCLUDE("libtidy/tidy.h", "CFLAGS_TIDY", null, null, true) + CHECK_HEADER("tidy.h", "CFLAGS_TIDY") || + CHECK_HEADER("tidy/tidy.h", "CFLAGS_TIDY", null, null, true) || + CHECK_HEADER("libtidy/tidy.h", "CFLAGS_TIDY", null, null, true) )) { - if (CHECK_HEADER_ADD_INCLUDE("tidybuffio.h", "CFLAGS_TIDY")) { + if (CHECK_HEADER("tidybuffio.h", "CFLAGS_TIDY")) { AC_DEFINE('HAVE_TIDYBUFFIO_H', 1, 'Define to 1 if you have the header file.'); } diff --git a/ext/xml/config.w32 b/ext/xml/config.w32 index 00ef36841c38..69fdcd4a0944 100644 --- a/ext/xml/config.w32 +++ b/ext/xml/config.w32 @@ -5,8 +5,8 @@ ARG_WITH("xml", "XML support", "yes"); if (PHP_XML == "yes") { if (PHP_LIBXML == "yes" && ADD_EXTENSION_DEP('xml', 'libxml') && - CHECK_HEADER_ADD_INCLUDE("libxml/parser.h", "CFLAGS_XML", PHP_PHP_BUILD + "\\include\\libxml2") && - CHECK_HEADER_ADD_INCLUDE("libxml/tree.h", "CFLAGS_XML", PHP_PHP_BUILD + "\\include\\libxml2") + CHECK_HEADER("libxml/parser.h", "CFLAGS_XML", PHP_PHP_BUILD + "\\include\\libxml2") && + CHECK_HEADER("libxml/tree.h", "CFLAGS_XML", PHP_PHP_BUILD + "\\include\\libxml2") ) { EXTENSION("xml", "xml.c compat.c", null, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1"); AC_DEFINE("HAVE_XML", 1, "Define to 1 if the PHP extension 'xml' is available."); diff --git a/ext/xmlreader/config.w32 b/ext/xmlreader/config.w32 index d92672d427da..803323931d6b 100644 --- a/ext/xmlreader/config.w32 +++ b/ext/xmlreader/config.w32 @@ -4,8 +4,8 @@ ARG_ENABLE("xmlreader", "XMLReader support", "yes"); if (PHP_XMLREADER == "yes" && PHP_LIBXML == "yes" && - CHECK_HEADER_ADD_INCLUDE("libxml/parser.h", "CFLAGS_XMLREADER", PHP_PHP_BUILD + "\\include\\libxml2") && - CHECK_HEADER_ADD_INCLUDE("libxml/tree.h", "CFLAGS_XMLREADER", PHP_PHP_BUILD + "\\include\\libxml2") + CHECK_HEADER("libxml/parser.h", "CFLAGS_XMLREADER", PHP_PHP_BUILD + "\\include\\libxml2") && + CHECK_HEADER("libxml/tree.h", "CFLAGS_XMLREADER", PHP_PHP_BUILD + "\\include\\libxml2") ) { EXTENSION("xmlreader", "php_xmlreader.c"); AC_DEFINE("HAVE_XMLREADER", 1, "Define to 1 if the PHP extension 'xmlreader' is available."); diff --git a/ext/xmlwriter/config.w32 b/ext/xmlwriter/config.w32 index 737e3fcd38c5..35459cdd9c4c 100644 --- a/ext/xmlwriter/config.w32 +++ b/ext/xmlwriter/config.w32 @@ -3,7 +3,7 @@ ARG_ENABLE("xmlwriter", "XMLWriter support", "yes"); if (PHP_XMLWRITER == "yes" && PHP_LIBXML == "yes") { - if (CHECK_HEADER_ADD_INCLUDE('libxml/xmlwriter.h', 'CFLAGS_XMLWRITER', PHP_XMLWRITER + ";" + PHP_PHP_BUILD + "\\include\\libxml2")) { + if (CHECK_HEADER('libxml/xmlwriter.h', 'CFLAGS_XMLWRITER', PHP_XMLWRITER + ";" + PHP_PHP_BUILD + "\\include\\libxml2")) { EXTENSION("xmlwriter", "php_xmlwriter.c"); AC_DEFINE("HAVE_XMLWRITER", 1, "Define to 1 if the PHP extension 'xmlwriter' is available."); if (!PHP_XMLWRITER_SHARED) { diff --git a/ext/xsl/config.w32 b/ext/xsl/config.w32 index 4990c3c5bd07..84d463decb94 100644 --- a/ext/xsl/config.w32 +++ b/ext/xsl/config.w32 @@ -6,7 +6,7 @@ if (PHP_XSL != "no") { if (PHP_DOM == "yes" && PHP_LIBXML == "yes" && ADD_EXTENSION_DEP('xsl', 'libxml') && ADD_EXTENSION_DEP('xsl', 'dom') - && CHECK_HEADER_ADD_INCLUDE("libxml/tree.h", "CFLAGS_XSL", PHP_PHP_BUILD + "\\include\\libxml2") + && CHECK_HEADER("libxml/tree.h", "CFLAGS_XSL", PHP_PHP_BUILD + "\\include\\libxml2") ) { var ext_xsl_lib_found = false; var ext_exslt_lib_found = false; @@ -25,9 +25,9 @@ if (PHP_XSL != "no") { } } - if (ext_xsl_lib_found && CHECK_HEADER_ADD_INCLUDE("libxslt\\xslt.h", "CFLAGS_XSL")) { + if (ext_xsl_lib_found && CHECK_HEADER("libxslt\\xslt.h", "CFLAGS_XSL")) { if (ext_exslt_lib_found) { - if (CHECK_HEADER_ADD_INCLUDE("libexslt\\exslt.h", "CFLAGS_XSL")) { + if (CHECK_HEADER("libexslt\\exslt.h", "CFLAGS_XSL")) { AC_DEFINE("HAVE_XSL_EXSLT", 1, "Define to 1 if the system has the EXSLT extension library for XSLT."); } } diff --git a/ext/zip/config.w32 b/ext/zip/config.w32 index 9b80aefaaad0..3f05d8454c1e 100644 --- a/ext/zip/config.w32 +++ b/ext/zip/config.w32 @@ -3,8 +3,8 @@ ARG_ENABLE("zip", "ZIP support", "yes,shared"); if (PHP_ZIP != "no") { - if (CHECK_HEADER_ADD_INCLUDE("zip.h", "CFLAGS_ZIP", PHP_PHP_BUILD + "\\include;" + PHP_EXTRA_INCLUDES) && - CHECK_HEADER_ADD_INCLUDE("zipconf.h", "CFLAGS_ZIP", PHP_PHP_BUILD + "\\lib\\libzip\\include;" + PHP_EXTRA_LIBS + "\\libzip\\include;" + PHP_ZIP) && + if (CHECK_HEADER("zip.h", "CFLAGS_ZIP", PHP_PHP_BUILD + "\\include;" + PHP_EXTRA_INCLUDES) && + CHECK_HEADER("zipconf.h", "CFLAGS_ZIP", PHP_PHP_BUILD + "\\lib\\libzip\\include;" + PHP_EXTRA_LIBS + "\\libzip\\include;" + PHP_ZIP) && (PHP_ZIP_SHARED && CHECK_LIB("libzip.lib", "zip", PHP_ZIP) || CHECK_LIB("libzip_a.lib", "zip", PHP_ZIP) && CHECK_LIB("libbz2_a.lib", "zip", PHP_ZIP) && CHECK_LIB("zlib_a.lib", "zip", PHP_ZIP) && CHECK_LIB("liblzma_a.lib", "zip", PHP_ZIP)) ) { diff --git a/ext/zlib/config.w32 b/ext/zlib/config.w32 index 63ca949813ce..520ab11cd84d 100644 --- a/ext/zlib/config.w32 +++ b/ext/zlib/config.w32 @@ -4,7 +4,7 @@ ARG_ENABLE("zlib", "ZLIB support", "yes"); if (PHP_ZLIB == "yes") { if (CHECK_LIB("zlib_a.lib;zlib.lib", "zlib", PHP_ZLIB) && - CHECK_HEADER_ADD_INCLUDE("zlib.h", "CFLAGS", "..\\zlib;" + php_usual_include_suspects)) { + CHECK_HEADER("zlib.h", "CFLAGS", "..\\zlib;" + php_usual_include_suspects)) { EXTENSION("zlib", "zlib.c zlib_fopen_wrapper.c zlib_filter.c", PHP_ZLIB_SHARED, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1"); AC_DEFINE("HAVE_ZLIB", 1, "Define to 1 if the PHP extension 'zlib' is available."); diff --git a/sapi/apache2handler/config.w32 b/sapi/apache2handler/config.w32 index 710d6438f53d..2ce4511666f1 100644 --- a/sapi/apache2handler/config.w32 +++ b/sapi/apache2handler/config.w32 @@ -10,7 +10,7 @@ if(PHP_APACHE2_4HANDLER != "no" && PHP_APACHE2HANDLER == "no") { if (PHP_APACHE2HANDLER != "no") { if (PHP_ZTS == "no") { WARNING("Apache module requires an --enable-zts build of PHP on windows"); - } else if (CHECK_HEADER_ADD_INCLUDE("httpd.h", "CFLAGS_APACHE2HANDLER", PHP_PHP_BUILD + "\\include\\apache2_4") && + } else if (CHECK_HEADER("httpd.h", "CFLAGS_APACHE2HANDLER", PHP_PHP_BUILD + "\\include\\apache2_4") && CHECK_LIB("libhttpd.lib", "apache2handler", PHP_PHP_BUILD + "\\lib\\apache2_4") && CHECK_LIB("libapr-1.lib", "apache2handler", PHP_PHP_BUILD + "\\lib\\apache2_4") && CHECK_LIB("libaprutil-1.lib", "apache2handler", PHP_PHP_BUILD + "\\lib\\apache2_4") diff --git a/sapi/cli/config.w32 b/sapi/cli/config.w32 index 093bf03a51d3..5dff4054b69d 100644 --- a/sapi/cli/config.w32 +++ b/sapi/cli/config.w32 @@ -12,7 +12,7 @@ if (PHP_CLI == "yes") { PHP_INSTALL_HEADERS("sapi/cli", "cli.h"); if (CHECK_LIB("edit_a.lib;edit.lib", "cli", PHP_CLI) && - CHECK_HEADER_ADD_INCLUDE("editline/readline.h", "CFLAGS_CLI")) { + CHECK_HEADER("editline/readline.h", "CFLAGS_CLI")) { ADD_FLAG("CFLAGS_CLI", "/D HAVE_LIBEDIT"); } } diff --git a/win32/build/confutils.js b/win32/build/confutils.js index e516fd410bcd..587d89c27f47 100644 --- a/win32/build/confutils.js +++ b/win32/build/confutils.js @@ -996,6 +996,55 @@ function GREP_HEADER(header_name, regex, path_to_check) return false; } +/** + * Checks if specified header exists and adds its include path to C flags. + */ +function CHECK_HEADER(header_name, flag_name, path_to_check, use_env, add_dir_part) +{ + var dir_part_to_add = ""; + + if (use_env == null) { + use_env = true; + } + + // if true, add the dir part of the header_name to the include path + if (add_dir_part == null) { + add_dir_part = false; + } else if (add_dir_part) { + var basename = FSO.GetFileName(header_name); + dir_part_to_add = "\\" + header_name.substr(0, header_name.length - basename.length - 1); + } + + if (path_to_check == null) { + path_to_check = php_usual_include_suspects; + } else { + path_to_check += ";" + php_usual_include_suspects; + } + + var p = search_paths(header_name, path_to_check, use_env ? "INCLUDE" : null); + + if (typeof(p) == "string") { + ADD_FLAG(flag_name, '/I "' + p + dir_part_to_add + '" '); + } else if (p == false) { + /* Not found in the defaults or the explicit paths, + * so check the general extra includes; if we find + * it here, no need to add another /I for it as we + * already have it covered, unless we are adding + * the dir part.... */ + p = search_paths(header_name, PHP_EXTRA_INCLUDES, null); + if (typeof(p) == "string" && add_dir_part) { + ADD_FLAG(flag_name, '/I "' + p + dir_part_to_add + '" '); + } + } + + return p; +} + +/** + * Obsolete. Checks if specified header exists, adds its include path to C flags + * and defines the 'HAVE_' C preprocessor macro. In new code, use + * CHECK_HEADER() instead, and define the 'HAVE_' macro manually as needed. + */ function CHECK_HEADER_ADD_INCLUDE(header_name, flag_name, path_to_check, use_env, add_dir_part, add_to_flag_only) { var dir_part_to_add = ""; @@ -3657,7 +3706,7 @@ function SETUP_ZLIB_LIB(target, path_to_check) return (PHP_ZLIB != "no" && !PHP_ZLIB_SHARED) || CHECK_LIB("zlib_a.lib;zlib.lib", target, path_to_check); } -function SETUP_OPENSSL(target, path_to_check, common_name, use_env, add_dir_part, add_to_flag_only) +function SETUP_OPENSSL(target, path_to_check, common_name, use_env, add_dir_part) { var ret = 0; var cflags_var = "CFLAGS_" + target.toUpperCase(); @@ -3665,7 +3714,7 @@ function SETUP_OPENSSL(target, path_to_check, common_name, use_env, add_dir_part if (CHECK_LIB("libcrypto.lib", target, path_to_check) && CHECK_LIB("libssl.lib", target, path_to_check) && CHECK_LIB("crypt32.lib", target, path_to_check, common_name) && - CHECK_HEADER_ADD_INCLUDE("openssl/ssl.h", cflags_var, path_to_check, use_env, add_dir_part, add_to_flag_only)) { + CHECK_HEADER("openssl/ssl.h", cflags_var, path_to_check, use_env, add_dir_part)) { /* Openssl 1.1.x or later */ return 2; } @@ -3678,8 +3727,8 @@ function SETUP_SQLITE3(target, path_to_check, shared) { var libs = (shared ? "libsqlite3.lib;libsqlite3_a.lib" : "libsqlite3_a.lib;libsqlite3.lib"); return CHECK_LIB(libs, target, path_to_check) && - CHECK_HEADER_ADD_INCLUDE("sqlite3.h", cflags_var) && - CHECK_HEADER_ADD_INCLUDE("sqlite3ext.h", cflags_var); + CHECK_HEADER("sqlite3.h", cflags_var) && + CHECK_HEADER("sqlite3ext.h", cflags_var); } function check_binary_tools_sdk()