diff --git a/Zend/Optimizer/zend_func_infos.h b/Zend/Optimizer/zend_func_infos.h
index 0fc33ae2f6e1c..3655e5fd21c35 100644
--- a/Zend/Optimizer/zend_func_infos.h
+++ b/Zend/Optimizer/zend_func_infos.h
@@ -518,9 +518,7 @@ static const func_info_t func_infos[] = {
 	F1("getcwd", MAY_BE_STRING|MAY_BE_FALSE),
 	F1("readdir", MAY_BE_STRING|MAY_BE_FALSE),
 	F1("scandir", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_OF_STRING|MAY_BE_FALSE),
-#if defined(HAVE_GLOB)
 	F1("glob", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_OF_STRING|MAY_BE_FALSE),
-#endif
 	F1("exec", MAY_BE_STRING|MAY_BE_FALSE),
 	F1("system", MAY_BE_STRING|MAY_BE_FALSE),
 	F1("escapeshellcmd", MAY_BE_STRING),
diff --git a/configure.ac b/configure.ac
index 01d9ded69b920..61d1c350a82be 100644
--- a/configure.ac
+++ b/configure.ac
@@ -557,6 +557,7 @@ AC_CHECK_FUNCS(m4_normalize([
   getwd
   glob
   gmtime_r
+  issetugid
   lchown
   localtime_r
   memcntl
@@ -571,6 +572,7 @@ AC_CHECK_FUNCS(m4_normalize([
   poll
   pthread_jit_write_protect_np
   putenv
+  reallocarray
   scandir
   setenv
   setitimer
@@ -591,6 +593,17 @@ AC_CHECK_FUNCS(m4_normalize([
   vasprintf
 ]))
 
+PHP_ARG_ENABLE([system-glob],
+  [whether to use the system glob function],
+  [AS_HELP_STRING([--enable-system-glob],
+    [Use the system glob function instead of the PHP provided replacement.])],
+  [no],
+  [no])
+
+AS_VAR_IF([PHP_SYSTEM_GLOB], [yes],
+  [AC_DEFINE([PHP_SYSTEM_GLOB], [1],
+    [Define to 1 if PHP will use the system glob function instead of php_glob.])])
+
 AC_CHECK_FUNC([inet_ntop],, [AC_MSG_FAILURE([Required inet_ntop not found.])])
 AC_CHECK_FUNC([inet_pton],, [AC_MSG_FAILURE([Required inet_pton not found.])])
 
@@ -1631,6 +1644,7 @@ PHP_ADD_SOURCES([main], m4_normalize([
     php_content_types.c
     php_ini_builder.c
     php_ini.c
+    php_glob.c
     php_odbc_utils.c
     php_open_temporary_file.c
     php_scandir.c
diff --git a/ext/ffi/ffi.c b/ext/ffi/ffi.c
index 621e60c6f19a3..10fc11f52e70f 100644
--- a/ext/ffi/ffi.c
+++ b/ext/ffi/ffi.c
@@ -45,13 +45,7 @@
 #endif
 #endif
 
-#ifdef HAVE_GLOB
-#ifdef PHP_WIN32
-#include "win32/glob.h"
-#else
-#include <glob.h>
-#endif
-#endif
+#include "php_glob.h"
 
 #ifndef __BIGGEST_ALIGNMENT__
 /* XXX need something better, perhaps with regard to SIMD, etc. */
@@ -5360,16 +5354,15 @@ ZEND_INI_END()
 
 static zend_result zend_ffi_preload_glob(const char *filename) /* {{{ */
 {
-#ifdef HAVE_GLOB
-	glob_t globbuf;
+	php_glob_t globbuf;
 	int    ret;
 	unsigned int i;
 
-	memset(&globbuf, 0, sizeof(glob_t));
+	memset(&globbuf, 0, sizeof(globbuf));
 
-	ret = glob(filename, 0, NULL, &globbuf);
-#ifdef GLOB_NOMATCH
-	if (ret == GLOB_NOMATCH || !globbuf.gl_pathc) {
+	ret = php_glob(filename, 0, NULL, &globbuf);
+#ifdef PHP_GLOB_NOMATCH
+	if (ret == PHP_GLOB_NOMATCH || !globbuf.gl_pathc) {
 #else
 	if (!globbuf.gl_pathc) {
 #endif
@@ -5378,20 +5371,13 @@ static zend_result zend_ffi_preload_glob(const char *filename) /* {{{ */
 		for(i=0 ; i<globbuf.gl_pathc; i++) {
 			zend_ffi *ffi = zend_ffi_load(globbuf.gl_pathv[i], 1);
 			if (!ffi) {
-				globfree(&globbuf);
+				php_globfree(&globbuf);
 				return FAILURE;
 			}
 			efree(ffi);
 		}
-		globfree(&globbuf);
+		php_globfree(&globbuf);
 	}
-#else
-	zend_ffi *ffi = zend_ffi_load(filename, 1);
-	if (!ffi) {
-		return FAILURE;
-	}
-	efree(ffi);
-#endif
 
 	return SUCCESS;
 }
diff --git a/ext/opcache/zend_accelerator_blacklist.c b/ext/opcache/zend_accelerator_blacklist.c
index c4a543e6207bb..b7ffb164cdd2b 100644
--- a/ext/opcache/zend_accelerator_blacklist.c
+++ b/ext/opcache/zend_accelerator_blacklist.c
@@ -30,13 +30,7 @@
 # define REGEX_MODE (REG_EXTENDED|REG_NOSUB)
 #endif
 
-#ifdef HAVE_GLOB
-#ifdef PHP_WIN32
-#include "win32/glob.h"
-#else
-#include <glob.h>
-#endif
-#endif
+#include "php_glob.h"
 
 #include "ext/pcre/php_pcre.h"
 
@@ -320,16 +314,15 @@ static void zend_accel_blacklist_loadone(zend_blacklist *blacklist, char *filena
 
 void zend_accel_blacklist_load(zend_blacklist *blacklist, char *filename)
 {
-#ifdef HAVE_GLOB
-	glob_t globbuf;
+	php_glob_t globbuf;
 	int    ret;
 	unsigned int i;
 
-	memset(&globbuf, 0, sizeof(glob_t));
+	memset(&globbuf, 0, sizeof(globbuf));
 
-	ret = glob(filename, 0, NULL, &globbuf);
-#ifdef GLOB_NOMATCH
-	if (ret == GLOB_NOMATCH || !globbuf.gl_pathc) {
+	ret = php_glob(filename, 0, NULL, &globbuf);
+#ifdef PHP_GLOB_NOMATCH
+	if (ret == PHP_GLOB_NOMATCH || !globbuf.gl_pathc) {
 #else
 	if (!globbuf.gl_pathc) {
 #endif
@@ -338,11 +331,8 @@ void zend_accel_blacklist_load(zend_blacklist *blacklist, char *filename)
 		for(i=0 ; i<globbuf.gl_pathc; i++) {
 			zend_accel_blacklist_loadone(blacklist, globbuf.gl_pathv[i]);
 		}
-		globfree(&globbuf);
+		php_globfree(&globbuf);
 	}
-#else
-	zend_accel_blacklist_loadone(blacklist, filename);
-#endif
 	zend_accel_blacklist_update_regexp(blacklist);
 }
 
diff --git a/ext/spl/spl_directory.c b/ext/spl/spl_directory.c
index 751000fe63004..2237dba86391e 100644
--- a/ext/spl/spl_directory.c
+++ b/ext/spl/spl_directory.c
@@ -211,7 +211,6 @@ static inline bool spl_intern_is_glob(const spl_filesystem_object *intern)
 
 PHPAPI zend_string *spl_filesystem_object_get_path(const spl_filesystem_object *intern) /* {{{ */
 {
-#ifdef HAVE_GLOB
 	if (intern->type == SPL_FS_DIR && spl_intern_is_glob(intern)) {
 		size_t len = 0;
 		char *tmp = php_glob_stream_get_path(intern->u.dir.dirp, &len);
@@ -220,7 +219,6 @@ PHPAPI zend_string *spl_filesystem_object_get_path(const spl_filesystem_object *
 		}
 		return zend_string_init(tmp, len, /* persistent */ false);
 	}
-#endif
 	if (!intern->path) {
 		return NULL;
 	}
@@ -641,14 +639,12 @@ static inline HashTable *spl_filesystem_object_get_debug_info(zend_object *objec
 		spl_set_private_debug_info_property(spl_ce_SplFileInfo, "fileName", strlen("fileName"), debug_info, &tmp);
 	}
 	if (intern->type == SPL_FS_DIR) {
-#ifdef HAVE_GLOB
 		if (spl_intern_is_glob(intern)) {
 			ZVAL_STR_COPY(&tmp, intern->path);
 		} else {
 			ZVAL_FALSE(&tmp);
 		}
 		spl_set_private_debug_info_property(spl_ce_DirectoryIterator, "glob", strlen("glob"), debug_info, &tmp);
-#endif
 		if (intern->u.dir.sub_path) {
 			ZVAL_STR_COPY(&tmp, intern->u.dir.sub_path);
 		} else {
@@ -721,13 +717,11 @@ static void spl_filesystem_object_construct(INTERNAL_FUNCTION_PARAMETERS, zend_l
 
 	/* spl_filesystem_dir_open() may emit an E_WARNING */
 	zend_replace_error_handling(EH_THROW, spl_ce_UnexpectedValueException, &error_handling);
-#ifdef HAVE_GLOB
 	if (SPL_HAS_FLAG(ctor_flags, DIT_CTOR_GLOB) && !zend_string_starts_with_literal(path, "glob://")) {
 		path = zend_strpprintf(0, "glob://%s", ZSTR_VAL(path));
 		spl_filesystem_dir_open(intern, path);
 		zend_string_release(path);
 	} else
-#endif
 	{
 		spl_filesystem_dir_open(intern, path);
 
@@ -1582,7 +1576,6 @@ PHP_METHOD(RecursiveDirectoryIterator, __construct)
 }
 /* }}} */
 
-#ifdef HAVE_GLOB
 /* {{{ Cronstructs a new dir iterator from a glob expression (no glob:// needed). */
 PHP_METHOD(GlobIterator, __construct)
 {
@@ -1607,7 +1600,6 @@ PHP_METHOD(GlobIterator, count)
 	}
 }
 /* }}} */
-#endif /* HAVE_GLOB */
 
 /* {{{ forward declarations to the iterator handlers */
 static void spl_filesystem_dir_it_dtor(zend_object_iterator *iter);
@@ -2782,11 +2774,9 @@ PHP_MINIT_FUNCTION(spl_directory)
 	spl_filesystem_object_check_handlers.clone_obj = NULL;
 	spl_filesystem_object_check_handlers.get_method = spl_filesystem_object_get_method_check;
 
-#ifdef HAVE_GLOB
 	spl_ce_GlobIterator = register_class_GlobIterator(spl_ce_FilesystemIterator, zend_ce_countable);
 	spl_ce_GlobIterator->create_object = spl_filesystem_object_new;
 	spl_ce_GlobIterator->default_object_handlers = &spl_filesystem_object_check_handlers;
-#endif
 
 	spl_ce_SplFileObject = register_class_SplFileObject(spl_ce_SplFileInfo, spl_ce_RecursiveIterator, spl_ce_SeekableIterator);
 	spl_ce_SplFileObject->default_object_handlers = &spl_filesystem_object_check_handlers;
diff --git a/ext/spl/spl_directory.stub.php b/ext/spl/spl_directory.stub.php
index e8ea5c4af9e81..6194a8617b438 100644
--- a/ext/spl/spl_directory.stub.php
+++ b/ext/spl/spl_directory.stub.php
@@ -207,7 +207,6 @@ public function getSubPath(): string {}
     public function getSubPathname(): string {}
 }
 
-#ifdef HAVE_GLOB
 class GlobIterator extends FilesystemIterator implements Countable
 {
     public function __construct(string $pattern, int $flags = FilesystemIterator::KEY_AS_PATHNAME | FilesystemIterator::CURRENT_AS_FILEINFO) {}
@@ -215,7 +214,6 @@ public function __construct(string $pattern, int $flags = FilesystemIterator::KE
     /** @tentative-return-type */
     public function count(): int {}
 }
-#endif
 
 class SplFileObject extends SplFileInfo implements RecursiveIterator, SeekableIterator
 {
diff --git a/ext/spl/spl_directory_arginfo.h b/ext/spl/spl_directory_arginfo.h
index e9287e7ea9483..55606b1a15397 100644
--- a/ext/spl/spl_directory_arginfo.h
+++ b/ext/spl/spl_directory_arginfo.h
@@ -1,5 +1,5 @@
 /* This is a generated file, edit the .stub.php file instead.
- * Stub hash: 06a7809f97dde10e800382fec03a9bb308918bb3 */
+ * Stub hash: 802429d736404c2d66601f640942c827b6e6e94b */
 
 ZEND_BEGIN_ARG_INFO_EX(arginfo_class_SplFileInfo___construct, 0, 0, 1)
 	ZEND_ARG_TYPE_INFO(0, filename, IS_STRING, 0)
@@ -151,15 +151,12 @@ ZEND_END_ARG_INFO()
 
 #define arginfo_class_RecursiveDirectoryIterator_getSubPathname arginfo_class_SplFileInfo_getPath
 
-#if defined(HAVE_GLOB)
 ZEND_BEGIN_ARG_INFO_EX(arginfo_class_GlobIterator___construct, 0, 0, 1)
 	ZEND_ARG_TYPE_INFO(0, pattern, IS_STRING, 0)
 	ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, flags, IS_LONG, 0, "FilesystemIterator::KEY_AS_PATHNAME | FilesystemIterator::CURRENT_AS_FILEINFO")
 ZEND_END_ARG_INFO()
 
-ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_GlobIterator_count, 0, 0, IS_LONG, 0)
-ZEND_END_ARG_INFO()
-#endif
+#define arginfo_class_GlobIterator_count arginfo_class_FilesystemIterator_getFlags
 
 ZEND_BEGIN_ARG_INFO_EX(arginfo_class_SplFileObject___construct, 0, 0, 1)
 	ZEND_ARG_TYPE_INFO(0, filename, IS_STRING, 0)
@@ -323,10 +320,8 @@ ZEND_METHOD(RecursiveDirectoryIterator, hasChildren);
 ZEND_METHOD(RecursiveDirectoryIterator, getChildren);
 ZEND_METHOD(RecursiveDirectoryIterator, getSubPath);
 ZEND_METHOD(RecursiveDirectoryIterator, getSubPathname);
-#if defined(HAVE_GLOB)
 ZEND_METHOD(GlobIterator, __construct);
 ZEND_METHOD(GlobIterator, count);
-#endif
 ZEND_METHOD(SplFileObject, __construct);
 ZEND_METHOD(SplFileObject, rewind);
 ZEND_METHOD(SplFileObject, eof);
@@ -430,13 +425,11 @@ static const zend_function_entry class_RecursiveDirectoryIterator_methods[] = {
 	ZEND_FE_END
 };
 
-#if defined(HAVE_GLOB)
 static const zend_function_entry class_GlobIterator_methods[] = {
 	ZEND_ME(GlobIterator, __construct, arginfo_class_GlobIterator___construct, ZEND_ACC_PUBLIC)
 	ZEND_ME(GlobIterator, count, arginfo_class_GlobIterator_count, ZEND_ACC_PUBLIC)
 	ZEND_FE_END
 };
-#endif
 
 static const zend_function_entry class_SplFileObject_methods[] = {
 	ZEND_ME(SplFileObject, __construct, arginfo_class_SplFileObject___construct, ZEND_ACC_PUBLIC)
@@ -602,7 +595,6 @@ static zend_class_entry *register_class_RecursiveDirectoryIterator(zend_class_en
 	return class_entry;
 }
 
-#if defined(HAVE_GLOB)
 static zend_class_entry *register_class_GlobIterator(zend_class_entry *class_entry_FilesystemIterator, zend_class_entry *class_entry_Countable)
 {
 	zend_class_entry ce, *class_entry;
@@ -613,7 +605,6 @@ static zend_class_entry *register_class_GlobIterator(zend_class_entry *class_ent
 
 	return class_entry;
 }
-#endif
 
 static zend_class_entry *register_class_SplFileObject(zend_class_entry *class_entry_SplFileInfo, zend_class_entry *class_entry_RecursiveIterator, zend_class_entry *class_entry_SeekableIterator)
 {
diff --git a/ext/standard/basic_functions.c b/ext/standard/basic_functions.c
index 19e3e29bedff3..f911fd1d32ed1 100644
--- a/ext/standard/basic_functions.c
+++ b/ext/standard/basic_functions.c
@@ -339,9 +339,7 @@ PHP_MINIT_FUNCTION(basic) /* {{{ */
 
 	php_register_url_stream_wrapper("php", &php_stream_php_wrapper);
 	php_register_url_stream_wrapper("file", &php_plain_files_wrapper);
-#ifdef HAVE_GLOB
 	php_register_url_stream_wrapper("glob", &php_glob_stream_wrapper);
-#endif
 	php_register_url_stream_wrapper("data", &php_stream_rfc2397_wrapper);
 	php_register_url_stream_wrapper("http", &php_stream_http_wrapper);
 	php_register_url_stream_wrapper("ftp", &php_stream_ftp_wrapper);
diff --git a/ext/standard/basic_functions.stub.php b/ext/standard/basic_functions.stub.php
index e7f4ff8844714..0a6f49f4f6221 100644
--- a/ext/standard/basic_functions.stub.php
+++ b/ext/standard/basic_functions.stub.php
@@ -2687,13 +2687,11 @@ function readdir($dir_handle = null): string|false {}
  */
 function scandir(string $directory, int $sorting_order = SCANDIR_SORT_ASCENDING, $context = null): array|false {}
 
-#ifdef HAVE_GLOB
 /**
  * @return array<int, string>|false
  * @refcount 1
  */
 function glob(string $pattern, int $flags = 0): array|false {}
-#endif
 
 /* exec.c */
 
diff --git a/ext/standard/basic_functions_arginfo.h b/ext/standard/basic_functions_arginfo.h
index 3d92288643159..c463d46c9fb7f 100644
--- a/ext/standard/basic_functions_arginfo.h
+++ b/ext/standard/basic_functions_arginfo.h
@@ -1,5 +1,5 @@
 /* This is a generated file, edit the .stub.php file instead.
- * Stub hash: 85677dc3476d25b7820fd3a26fe39f2e9378b6e7 */
+ * Stub hash: 60b709317fc9a1b9e7c36bc4afd1a6cd41dfc08a */
 
 ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_set_time_limit, 0, 1, _IS_BOOL, 0)
 	ZEND_ARG_TYPE_INFO(0, seconds, IS_LONG, 0)
@@ -1127,12 +1127,10 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_scandir, 0, 1, MAY_BE_ARRAY|MAY_
 	ZEND_ARG_INFO_WITH_DEFAULT_VALUE(0, context, "null")
 ZEND_END_ARG_INFO()
 
-#if defined(HAVE_GLOB)
 ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_glob, 0, 1, MAY_BE_ARRAY|MAY_BE_FALSE)
 	ZEND_ARG_TYPE_INFO(0, pattern, IS_STRING, 0)
 	ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, flags, IS_LONG, 0, "0")
 ZEND_END_ARG_INFO()
-#endif
 
 ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_exec, 0, 1, MAY_BE_STRING|MAY_BE_FALSE)
 	ZEND_ARG_TYPE_INFO(0, command, IS_STRING, 0)
@@ -2592,9 +2590,7 @@ ZEND_FUNCTION(getcwd);
 ZEND_FUNCTION(rewinddir);
 ZEND_FUNCTION(readdir);
 ZEND_FUNCTION(scandir);
-#if defined(HAVE_GLOB)
 ZEND_FUNCTION(glob);
-#endif
 ZEND_FUNCTION(exec);
 ZEND_FUNCTION(system);
 ZEND_FUNCTION(passthru);
@@ -3193,9 +3189,7 @@ static const zend_function_entry ext_functions[] = {
 	ZEND_FE(rewinddir, arginfo_rewinddir)
 	ZEND_FE(readdir, arginfo_readdir)
 	ZEND_FE(scandir, arginfo_scandir)
-#if defined(HAVE_GLOB)
 	ZEND_FE(glob, arginfo_glob)
-#endif
 	ZEND_FE(exec, arginfo_exec)
 	ZEND_FE(system, arginfo_system)
 	ZEND_FE(passthru, arginfo_passthru)
diff --git a/ext/standard/dir.c b/ext/standard/dir.c
index b468681ac364a..cced88e4ac8a5 100644
--- a/ext/standard/dir.c
+++ b/ext/standard/dir.c
@@ -397,7 +397,6 @@ PHP_FUNCTION(getcwd)
 }
 /* }}} */
 
-#ifdef HAVE_GLOB
 /* {{{ Find pathnames matching a pattern */
 PHP_FUNCTION(glob)
 {
@@ -410,7 +409,7 @@ PHP_FUNCTION(glob)
 	char *pattern = NULL;
 	size_t pattern_len;
 	zend_long flags = 0;
-	glob_t globbuf;
+	php_glob_t globbuf;
 	size_t n;
 	int ret;
 	bool basedir_limit = 0;
@@ -427,7 +426,7 @@ PHP_FUNCTION(glob)
 		RETURN_FALSE;
 	}
 
-	if ((GLOB_AVAILABLE_FLAGS & flags) != flags) {
+	if ((PHP_GLOB_AVAILABLE_FLAGS & flags) != flags) {
 		php_error_docref(NULL, E_WARNING, "At least one of the passed flags is invalid or not supported on this platform");
 		RETURN_FALSE;
 	}
@@ -451,14 +450,14 @@ PHP_FUNCTION(glob)
 #endif
 
 
-	memset(&globbuf, 0, sizeof(glob_t));
+	memset(&globbuf, 0, sizeof(globbuf));
 	globbuf.gl_offs = 0;
-	if (0 != (ret = glob(pattern, flags & GLOB_FLAGMASK, NULL, &globbuf))) {
-#ifdef GLOB_NOMATCH
-		if (GLOB_NOMATCH == ret) {
+	if (0 != (ret = php_glob(pattern, flags & PHP_GLOB_FLAGMASK, NULL, &globbuf))) {
+#ifdef PHP_GLOB_NOMATCH
+		if (PHP_GLOB_NOMATCH == ret) {
 			/* Some glob implementation simply return no data if no matches
-			   were found, others return the GLOB_NOMATCH error code.
-			   We don't want to treat GLOB_NOMATCH as an error condition
+			   were found, others return the PHP_GLOB_NOMATCH error code.
+			   We don't want to treat PHP_GLOB_NOMATCH as an error condition
 			   so that PHP glob() behaves the same on both types of
 			   implementations and so that 'foreach (glob() as ...'
 			   can be used for simple glob() calls without further error
@@ -472,7 +471,7 @@ PHP_FUNCTION(glob)
 
 	/* now catch the FreeBSD style of "no matches" */
 	if (!globbuf.gl_pathc || !globbuf.gl_pathv) {
-#ifdef GLOB_NOMATCH
+#ifdef PHP_GLOB_NOMATCH
 no_results:
 #endif
 		array_init(return_value);
@@ -487,7 +486,7 @@ PHP_FUNCTION(glob)
 				continue;
 			}
 		}
-		/* we need to do this every time since GLOB_ONLYDIR does not guarantee that
+		/* we need to do this every time since PHP_GLOB_ONLYDIR does not guarantee that
 		 * all directories will be filtered. GNU libc documentation states the
 		 * following:
 		 * If the information about the type of the file is easily available
@@ -495,7 +494,7 @@ PHP_FUNCTION(glob)
 		 * determine the information for each file. I.e., the caller must still be
 		 * able to filter directories out.
 		 */
-		if (flags & GLOB_ONLYDIR) {
+		if (flags & PHP_GLOB_ONLYDIR) {
 			zend_stat_t s = {0};
 
 			if (0 != VCWD_STAT(globbuf.gl_pathv[n], &s)) {
@@ -510,7 +509,7 @@ PHP_FUNCTION(glob)
 		zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &tmp);
 	}
 
-	globfree(&globbuf);
+	php_globfree(&globbuf);
 
 	if (basedir_limit && !zend_hash_num_elements(Z_ARRVAL_P(return_value))) {
 		zend_array_destroy(Z_ARR_P(return_value));
@@ -518,7 +517,6 @@ PHP_FUNCTION(glob)
 	}
 }
 /* }}} */
-#endif
 
 /* {{{ List files & directories inside the specified path */
 PHP_FUNCTION(scandir)
diff --git a/ext/standard/dir.stub.php b/ext/standard/dir.stub.php
index afca1fcacc421..6b5ef51c13bbb 100644
--- a/ext/standard/dir.stub.php
+++ b/ext/standard/dir.stub.php
@@ -13,64 +13,62 @@
  */
 const PATH_SEPARATOR = UNKNOWN;
 
-#ifdef HAVE_GLOB
-#if (defined(GLOB_BRACE) && GLOB_BRACE != 0)
+#if (defined(PHP_GLOB_BRACE) && PHP_GLOB_BRACE != 0)
 /**
  * @var int
- * @cvalue GLOB_BRACE
+ * @cvalue PHP_GLOB_BRACE
  */
 const GLOB_BRACE = UNKNOWN;
 #endif
-#if (defined(GLOB_ERR) && GLOB_ERR != 0)
+#if (defined(PHP_GLOB_ERR) && PHP_GLOB_ERR != 0)
 /**
  * @var int
- * @cvalue GLOB_ERR
+ * @cvalue PHP_GLOB_ERR
  */
 const GLOB_ERR = UNKNOWN;
 #endif
-#if (defined(GLOB_MARK) && GLOB_MARK != 0)
+#if (defined(PHP_GLOB_MARK) && PHP_GLOB_MARK != 0)
 /**
  * @var int
- * @cvalue GLOB_MARK
+ * @cvalue PHP_GLOB_MARK
  */
 const GLOB_MARK = UNKNOWN;
 #endif
-#if (defined(GLOB_NOCHECK) && GLOB_NOCHECK != 0)
+#if (defined(PHP_GLOB_NOCHECK) && PHP_GLOB_NOCHECK != 0)
 /**
  * @var int
- * @cvalue GLOB_NOCHECK
+ * @cvalue PHP_GLOB_NOCHECK
  */
 const GLOB_NOCHECK = UNKNOWN;
 #endif
-#if (defined(GLOB_NOESCAPE) && GLOB_NOESCAPE != 0)
+#if (defined(PHP_GLOB_NOESCAPE) && PHP_GLOB_NOESCAPE != 0)
 /**
  * @var int
- * @cvalue GLOB_NOESCAPE
+ * @cvalue PHP_GLOB_NOESCAPE
  */
 const GLOB_NOESCAPE = UNKNOWN;
 #endif
-#if (defined(GLOB_NOSORT) && GLOB_NOSORT != 0)
+#if (defined(PHP_GLOB_NOSORT) && PHP_GLOB_NOSORT != 0)
 /**
  * @var int
- * @cvalue GLOB_NOSORT
+ * @cvalue PHP_GLOB_NOSORT
  */
 const GLOB_NOSORT = UNKNOWN;
 #endif
-#ifdef GLOB_ONLYDIR
+#if (defined(PHP_GLOB_ONLYDIR) && PHP_GLOB_ONLYDIR != 0)
 /**
  * @var int
- * @cvalue GLOB_ONLYDIR
+ * @cvalue PHP_GLOB_ONLYDIR
  */
 const GLOB_ONLYDIR = UNKNOWN;
 #endif
-#ifdef GLOB_AVAILABLE_FLAGS
+#ifdef PHP_GLOB_AVAILABLE_FLAGS
 /**
  * @var int
- * @cvalue GLOB_AVAILABLE_FLAGS
+ * @cvalue PHP_GLOB_AVAILABLE_FLAGS
  */
 const GLOB_AVAILABLE_FLAGS = UNKNOWN;
 #endif
-#endif
 /**
  * @var int
  * @cvalue PHP_SCANDIR_SORT_ASCENDING
diff --git a/ext/standard/dir_arginfo.h b/ext/standard/dir_arginfo.h
index f73b0e5d86ad1..703088d1eb0d5 100644
--- a/ext/standard/dir_arginfo.h
+++ b/ext/standard/dir_arginfo.h
@@ -1,5 +1,5 @@
 /* This is a generated file, edit the .stub.php file instead.
- * Stub hash: 543d0d12062ed88dab7a3ac4354499682c5c7166 */
+ * Stub hash: e21d382cd4001001874c49d8c5244efb57613910 */
 
 ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Directory_close, 0, 0, IS_VOID, 0)
 ZEND_END_ARG_INFO()
@@ -24,29 +24,29 @@ static void register_dir_symbols(int module_number)
 {
 	REGISTER_STRING_CONSTANT("DIRECTORY_SEPARATOR", dirsep_str, CONST_PERSISTENT);
 	REGISTER_STRING_CONSTANT("PATH_SEPARATOR", pathsep_str, CONST_PERSISTENT);
-#if defined(HAVE_GLOB) && (defined(GLOB_BRACE) && GLOB_BRACE != 0)
-	REGISTER_LONG_CONSTANT("GLOB_BRACE", GLOB_BRACE, CONST_PERSISTENT);
+#if (defined(PHP_GLOB_BRACE) && PHP_GLOB_BRACE != 0)
+	REGISTER_LONG_CONSTANT("GLOB_BRACE", PHP_GLOB_BRACE, CONST_PERSISTENT);
 #endif
-#if defined(HAVE_GLOB) && (defined(GLOB_ERR) && GLOB_ERR != 0)
-	REGISTER_LONG_CONSTANT("GLOB_ERR", GLOB_ERR, CONST_PERSISTENT);
+#if (defined(PHP_GLOB_ERR) && PHP_GLOB_ERR != 0)
+	REGISTER_LONG_CONSTANT("GLOB_ERR", PHP_GLOB_ERR, CONST_PERSISTENT);
 #endif
-#if defined(HAVE_GLOB) && (defined(GLOB_MARK) && GLOB_MARK != 0)
-	REGISTER_LONG_CONSTANT("GLOB_MARK", GLOB_MARK, CONST_PERSISTENT);
+#if (defined(PHP_GLOB_MARK) && PHP_GLOB_MARK != 0)
+	REGISTER_LONG_CONSTANT("GLOB_MARK", PHP_GLOB_MARK, CONST_PERSISTENT);
 #endif
-#if defined(HAVE_GLOB) && (defined(GLOB_NOCHECK) && GLOB_NOCHECK != 0)
-	REGISTER_LONG_CONSTANT("GLOB_NOCHECK", GLOB_NOCHECK, CONST_PERSISTENT);
+#if (defined(PHP_GLOB_NOCHECK) && PHP_GLOB_NOCHECK != 0)
+	REGISTER_LONG_CONSTANT("GLOB_NOCHECK", PHP_GLOB_NOCHECK, CONST_PERSISTENT);
 #endif
-#if defined(HAVE_GLOB) && (defined(GLOB_NOESCAPE) && GLOB_NOESCAPE != 0)
-	REGISTER_LONG_CONSTANT("GLOB_NOESCAPE", GLOB_NOESCAPE, CONST_PERSISTENT);
+#if (defined(PHP_GLOB_NOESCAPE) && PHP_GLOB_NOESCAPE != 0)
+	REGISTER_LONG_CONSTANT("GLOB_NOESCAPE", PHP_GLOB_NOESCAPE, CONST_PERSISTENT);
 #endif
-#if defined(HAVE_GLOB) && (defined(GLOB_NOSORT) && GLOB_NOSORT != 0)
-	REGISTER_LONG_CONSTANT("GLOB_NOSORT", GLOB_NOSORT, CONST_PERSISTENT);
+#if (defined(PHP_GLOB_NOSORT) && PHP_GLOB_NOSORT != 0)
+	REGISTER_LONG_CONSTANT("GLOB_NOSORT", PHP_GLOB_NOSORT, CONST_PERSISTENT);
 #endif
-#if defined(HAVE_GLOB) && defined(GLOB_ONLYDIR)
-	REGISTER_LONG_CONSTANT("GLOB_ONLYDIR", GLOB_ONLYDIR, CONST_PERSISTENT);
+#if (defined(PHP_GLOB_ONLYDIR) && PHP_GLOB_ONLYDIR != 0)
+	REGISTER_LONG_CONSTANT("GLOB_ONLYDIR", PHP_GLOB_ONLYDIR, CONST_PERSISTENT);
 #endif
-#if defined(HAVE_GLOB) && defined(GLOB_AVAILABLE_FLAGS)
-	REGISTER_LONG_CONSTANT("GLOB_AVAILABLE_FLAGS", GLOB_AVAILABLE_FLAGS, CONST_PERSISTENT);
+#if defined(PHP_GLOB_AVAILABLE_FLAGS)
+	REGISTER_LONG_CONSTANT("GLOB_AVAILABLE_FLAGS", PHP_GLOB_AVAILABLE_FLAGS, CONST_PERSISTENT);
 #endif
 	REGISTER_LONG_CONSTANT("SCANDIR_SORT_ASCENDING", PHP_SCANDIR_SORT_ASCENDING, CONST_PERSISTENT);
 	REGISTER_LONG_CONSTANT("SCANDIR_SORT_DESCENDING", PHP_SCANDIR_SORT_DESCENDING, CONST_PERSISTENT);
diff --git a/ext/standard/php_dir_int.h b/ext/standard/php_dir_int.h
index f9d63e78661a1..06faf4e678f42 100644
--- a/ext/standard/php_dir_int.h
+++ b/ext/standard/php_dir_int.h
@@ -17,52 +17,7 @@
 #ifndef PHP_DIR_INT_H
 #define PHP_DIR_INT_H
 
-#ifdef HAVE_GLOB
-#ifndef PHP_WIN32
-#include <glob.h>
-#else
-#include "win32/glob.h"
-#endif
-#endif
-
-#ifdef HAVE_GLOB
-
-#ifndef GLOB_BRACE
-#define GLOB_BRACE 0
-#endif
-
-#ifndef GLOB_ERR
-#define GLOB_ERR 0
-#endif
-
-#ifndef GLOB_MARK
-#define GLOB_MARK 0
-#endif
-
-#ifndef GLOB_NOCHECK
-#define GLOB_NOCHECK 0
-#endif
-
-#ifndef GLOB_NOESCAPE
-#define GLOB_NOESCAPE 0
-#endif
-
-#ifndef GLOB_NOSORT
-#define GLOB_NOSORT 0
-#endif
-
-#ifndef GLOB_ONLYDIR
-#define GLOB_ONLYDIR (1<<30)
-#define GLOB_EMULATE_ONLYDIR
-#define GLOB_FLAGMASK (~GLOB_ONLYDIR)
-#else
-#define GLOB_FLAGMASK (~0)
-#endif
-
-/* This is used for checking validity of passed flags (passing invalid flags causes segfault in glob()!! */
-#define GLOB_AVAILABLE_FLAGS (0 | GLOB_BRACE | GLOB_MARK | GLOB_NOSORT | GLOB_NOCHECK | GLOB_NOESCAPE | GLOB_ERR | GLOB_ONLYDIR)
-
-#endif /* HAVE_GLOB */
+#include "php_glob.h"
 
 char dirsep_str[2], pathsep_str[2];
 
diff --git a/ext/zip/php_zip.c b/ext/zip/php_zip.c
index 187104d2da4ed..807a454073551 100644
--- a/ext/zip/php_zip.c
+++ b/ext/zip/php_zip.c
@@ -30,13 +30,7 @@
 #include "php_zip.h"
 #include "php_zip_arginfo.h"
 
-#ifdef HAVE_GLOB
-#ifndef PHP_WIN32
-#include <glob.h>
-#else
-#include "win32/glob.h"
-#endif
-#endif
+#include "php_glob.h"
 
 /* {{{ Resource le */
 static int le_zip_dir;
@@ -580,48 +574,15 @@ static char * php_zipobj_get_zip_comment(ze_zip_object *obj, int *len) /* {{{ */
 }
 /* }}} */
 
-#ifdef HAVE_GLOB /* {{{ */
-#ifndef GLOB_ONLYDIR
-#define GLOB_ONLYDIR (1<<30)
-#define GLOB_EMULATE_ONLYDIR
-#define GLOB_FLAGMASK (~GLOB_ONLYDIR)
-#else
-#define GLOB_FLAGMASK (~0)
-#endif
-#ifndef GLOB_BRACE
-# define GLOB_BRACE 0
-#endif
-#ifndef GLOB_MARK
-# define GLOB_MARK 0
-#endif
-#ifndef GLOB_NOSORT
-# define GLOB_NOSORT 0
-#endif
-#ifndef GLOB_NOCHECK
-# define GLOB_NOCHECK 0
-#endif
-#ifndef GLOB_NOESCAPE
-# define GLOB_NOESCAPE 0
-#endif
-#ifndef GLOB_ERR
-# define GLOB_ERR 0
-#endif
-
-/* This is used for checking validity of passed flags (passing invalid flags causes segfault in glob()!! */
-#define GLOB_AVAILABLE_FLAGS (0 | GLOB_BRACE | GLOB_MARK | GLOB_NOSORT | GLOB_NOCHECK | GLOB_NOESCAPE | GLOB_ERR | GLOB_ONLYDIR)
-
-#endif /* }}} */
-
 int php_zip_glob(char *pattern, int pattern_len, zend_long flags, zval *return_value) /* {{{ */
 {
-#ifdef HAVE_GLOB
 	int cwd_skip = 0;
 #ifdef ZTS
 	char cwd[MAXPATHLEN];
 	char work_pattern[MAXPATHLEN];
 	char *result;
 #endif
-	glob_t globbuf;
+	php_glob_t globbuf;
 	size_t n;
 	int ret;
 
@@ -630,7 +591,7 @@ int php_zip_glob(char *pattern, int pattern_len, zend_long flags, zval *return_v
 		return -1;
 	}
 
-	if ((GLOB_AVAILABLE_FLAGS & flags) != flags) {
+	if ((PHP_GLOB_AVAILABLE_FLAGS & flags) != flags) {
 
 		php_error_docref(NULL, E_WARNING, "At least one of the passed flags is invalid or not supported on this platform");
 		return -1;
@@ -655,12 +616,12 @@ int php_zip_glob(char *pattern, int pattern_len, zend_long flags, zval *return_v
 #endif
 
 	globbuf.gl_offs = 0;
-	if (0 != (ret = glob(pattern, flags & GLOB_FLAGMASK, NULL, &globbuf))) {
-#ifdef GLOB_NOMATCH
-		if (GLOB_NOMATCH == ret) {
+	if (0 != (ret = php_glob(pattern, flags & PHP_GLOB_FLAGMASK, NULL, &globbuf))) {
+#ifdef PHP_GLOB_NOMATCH
+		if (PHP_GLOB_NOMATCH == ret) {
 			/* Some glob implementation simply return no data if no matches
-			   were found, others return the GLOB_NOMATCH error code.
-			   We don't want to treat GLOB_NOMATCH as an error condition
+			   were found, others return the PHP_GLOB_NOMATCH error code.
+			   We don't want to treat PHP_GLOB_NOMATCH as an error condition
 			   so that PHP glob() behaves the same on both types of
 			   implementations and so that 'foreach (glob() as ...'
 			   can be used for simple glob() calls without further error
@@ -687,7 +648,7 @@ int php_zip_glob(char *pattern, int pattern_len, zend_long flags, zval *return_v
 
 	array_init(return_value);
 	for (n = 0; n < globbuf.gl_pathc; n++) {
-		/* we need to do this every time since GLOB_ONLYDIR does not guarantee that
+		/* we need to do this every time since PHP_GLOB_ONLYDIR does not guarantee that
 		 * all directories will be filtered. GNU libc documentation states the
 		 * following:
 		 * If the information about the type of the file is easily available
@@ -695,7 +656,7 @@ int php_zip_glob(char *pattern, int pattern_len, zend_long flags, zval *return_v
 		 * determine the information for each file. I.e., the caller must still be
 		 * able to filter directories out.
 		 */
-		if (flags & GLOB_ONLYDIR) {
+		if (flags & PHP_GLOB_ONLYDIR) {
 			zend_stat_t s = {0};
 
 			if (0 != VCWD_STAT(globbuf.gl_pathv[n], &s)) {
@@ -710,12 +671,8 @@ int php_zip_glob(char *pattern, int pattern_len, zend_long flags, zval *return_v
 	}
 
 	ret = globbuf.gl_pathc;
-	globfree(&globbuf);
+	php_globfree(&globbuf);
 	return ret;
-#else
-	zend_throw_error(NULL, "Glob support is not available");
-	return 0;
-#endif  /* HAVE_GLOB */
 }
 /* }}} */
 
diff --git a/win32/charclass.h b/main/charclass.h
similarity index 100%
rename from win32/charclass.h
rename to main/charclass.h
diff --git a/win32/glob.c b/main/php_glob.c
similarity index 84%
rename from win32/glob.c
rename to main/php_glob.c
index 8a04b8de18c24..f84a511621c4d 100644
--- a/win32/glob.c
+++ b/main/php_glob.c
@@ -37,24 +37,29 @@
  *
  * Optional extra services, controlled by flags not defined by POSIX:
  *
- * GLOB_QUOTE:
+ * PHP_GLOB_QUOTE:
  *	Escaping convention: \ inhibits any special meaning the following
  *	character might have (except \ at end of string is retained).
- * GLOB_MAGCHAR:
+ * PHP_GLOB_MAGCHAR:
  *	Set in gl_flags if pattern contained a globbing character.
- * GLOB_NOMAGIC:
- *	Same as GLOB_NOCHECK, but it will only append pattern if it did
+ * PHP_GLOB_NOMAGIC:
+ *	Same as PHP_GLOB_NOCHECK, but it will only append pattern if it did
  *	not contain any magic characters.  [Used in csh style globbing]
- * GLOB_ALTDIRFUNC:
+ * PHP_GLOB_ALTDIRFUNC:
  *	Use alternately specified directory access functions.
- * GLOB_TILDE:
+ * PHP_GLOB_TILDE:
  *	expand ~user/foo to the /home/dir/of/user/foo
- * GLOB_BRACE:
+ * PHP_GLOB_BRACE:
  *	expand {1,2}{a,b} to 1a 1b 2a 2b
  * gl_matchc:
  *	Number of matches in the current invocation of glob.
  */
 
+#include "php_glob.h"
+
+#if defined(HAVE_GLOB) && defined(PHP_SYSTEM_GLOB)
+#else
+
 #ifdef PHP_WIN32
 #if _MSC_VER < 1800
 # define _POSIX_
@@ -79,6 +84,11 @@
 # endif
 #endif
 
+#ifndef _PW_BUF_LEN
+/* XXX: Should be sysconf(_SC_GETPW_R_SIZE_MAX), but then VLA */
+#define _PW_BUF_LEN 4096
+#endif
+
 #include "php.h"
 #include <sys/stat.h>
 
@@ -90,7 +100,6 @@
 #include <unistd.h>
 #endif
 #include <errno.h>
-#include "glob.h"
 #include <limits.h>
 #include <stdint.h>
 #include <stdio.h>
@@ -149,9 +158,9 @@ typedef char Char;
 #define	M_CLASS		META(':')
 #define	ismeta(c)	(((c)&M_QUOTE) != 0)
 
-#define	GLOB_LIMIT_MALLOC	65536
-#define	GLOB_LIMIT_STAT		2048
-#define	GLOB_LIMIT_READDIR	16384
+#define	PHP_GLOB_LIMIT_MALLOC	65536
+#define	PHP_GLOB_LIMIT_STAT		2048
+#define	PHP_GLOB_LIMIT_READDIR	16384
 
 struct glob_lim {
 	size_t	glim_malloc;
@@ -164,6 +173,7 @@ struct glob_path_stat {
 	zend_stat_t	*gps_stat;
 };
 
+#ifndef HAVE_REALLOCARRAY
 /*
  * XXX: This is temporary to avoid having reallocarray be imported and part of
  * PHP's public API. Since it's only needed here and on Windows, we can just
@@ -204,33 +214,34 @@ reallocarray(void *optr, size_t nmemb, size_t size)
 	}
 	return realloc(optr, size * nmemb);
 }
+#endif
 
 static int	 compare(const void *, const void *);
 static int	 compare_gps(const void *, const void *);
 static int	 g_Ctoc(const Char *, char *, size_t);
-static int	 g_lstat(Char *, zend_stat_t *, glob_t *);
-static DIR	*g_opendir(Char *, glob_t *);
+static int	 g_lstat(Char *, zend_stat_t *, php_glob_t *);
+static DIR	*g_opendir(Char *, php_glob_t *);
 static Char	*g_strchr(const Char *, int);
 static int	 g_strncmp(const Char *, const char *, size_t);
-static int	 g_stat(Char *, zend_stat_t *, glob_t *);
-static int	 glob0(const Char *, glob_t *, struct glob_lim *);
-static int	 glob1(Char *, Char *, glob_t *, struct glob_lim *);
+static int	 g_stat(Char *, zend_stat_t *, php_glob_t *);
+static int	 glob0(const Char *, php_glob_t *, struct glob_lim *);
+static int	 glob1(Char *, Char *, php_glob_t *, struct glob_lim *);
 static int	 glob2(Char *, Char *, Char *, Char *, Char *, Char *,
-				glob_t *, struct glob_lim *);
+				php_glob_t *, struct glob_lim *);
 static int	 glob3(Char *, Char *, Char *, Char *, Char *,
-				Char *, Char *, glob_t *, struct glob_lim *);
-static int	 globextend(const Char *, glob_t *, struct glob_lim *,
+				Char *, Char *, php_glob_t *, struct glob_lim *);
+static int	 globextend(const Char *, php_glob_t *, struct glob_lim *,
 				zend_stat_t *);
-static const Char *globtilde(const Char *, Char *, size_t, glob_t *);
-static int	 globexp1(const Char *, glob_t *, struct glob_lim *);
-static int	 globexp2(const Char *, const Char *, glob_t *,
+static const Char *globtilde(const Char *, Char *, size_t, php_glob_t *);
+static int	 globexp1(const Char *, php_glob_t *, struct glob_lim *);
+static int	 globexp2(const Char *, const Char *, php_glob_t *,
 				struct glob_lim *);
 static int	 match(Char *, Char *, Char *);
 #ifdef DEBUG
 static void	 qprintf(const char *, Char *);
 #endif
 
-PHPAPI int glob(const char *pattern, int flags, int (*errfunc)(const char *, int), glob_t *pglob)
+PHPAPI int php_glob(const char *pattern, int flags, int (*errfunc)(const char *, int), php_glob_t *pglob)
 {
 	const uint8_t *patnext;
 	int c;
@@ -241,31 +252,31 @@ PHPAPI int glob(const char *pattern, int flags, int (*errfunc)(const char *, int
 	/* Force skipping escape sequences on windows
 	 * due to the ambiguity with path backslashes
 	 */
-	flags |= GLOB_NOESCAPE;
+	flags |= PHP_GLOB_NOESCAPE;
 #endif
 
 	patnext = (uint8_t *) pattern;
-	if (!(flags & GLOB_APPEND)) {
+	if (!(flags & PHP_GLOB_APPEND)) {
 		pglob->gl_pathc = 0;
 		pglob->gl_pathv = NULL;
 		pglob->gl_statv = NULL;
-		if (!(flags & GLOB_DOOFFS))
+		if (!(flags & PHP_GLOB_DOOFFS))
 			pglob->gl_offs = 0;
 	}
-	pglob->gl_flags = flags & ~GLOB_MAGCHAR;
+	pglob->gl_flags = flags & ~PHP_GLOB_MAGCHAR;
 	pglob->gl_errfunc = errfunc;
 	pglob->gl_matchc = 0;
 
 	if (strnlen(pattern, PATH_MAX) == PATH_MAX)
-		return(GLOB_NOMATCH);
+		return(PHP_GLOB_NOMATCH);
 
 	if (pglob->gl_offs >= SSIZE_MAX || pglob->gl_pathc >= SSIZE_MAX ||
 		pglob->gl_pathc >= SSIZE_MAX - pglob->gl_offs - 1)
-		return GLOB_NOSPACE;
+		return PHP_GLOB_NOSPACE;
 
 	bufnext = patbuf;
 	bufend = bufnext + PATH_MAX - 1;
-	if (flags & GLOB_NOESCAPE)
+	if (flags & PHP_GLOB_NOESCAPE)
 		while (bufnext < bufend && (c = *patnext++) != EOS)
 			*bufnext++ = c;
 	else {
@@ -282,7 +293,7 @@ PHPAPI int glob(const char *pattern, int flags, int (*errfunc)(const char *, int
 	}
 	*bufnext = EOS;
 
-	if (flags & GLOB_BRACE)
+	if (flags & PHP_GLOB_BRACE)
 		return globexp1(patbuf, pglob, &limit);
 	else
 		return glob0(patbuf, pglob, &limit);
@@ -293,7 +304,7 @@ PHPAPI int glob(const char *pattern, int flags, int (*errfunc)(const char *, int
  * invoke the standard globbing routine to glob the rest of the magic
  * characters
  */
-static int globexp1(const Char *pattern, glob_t *pglob, struct glob_lim *limitp)
+static int globexp1(const Char *pattern, php_glob_t *pglob, struct glob_lim *limitp)
 {
 	const Char* ptr = pattern;
 
@@ -313,7 +324,7 @@ static int globexp1(const Char *pattern, glob_t *pglob, struct glob_lim *limitp)
  * If it succeeds then it invokes globexp1 with the new pattern.
  * If it fails then it tries to glob the rest of the pattern and returns.
  */
-static int globexp2(const Char *ptr, const Char *pattern, glob_t *pglob, struct glob_lim *limitp)
+static int globexp2(const Char *ptr, const Char *pattern, php_glob_t *pglob, struct glob_lim *limitp)
 {
 	int     i, rv;
 	Char   *lm, *ls;
@@ -398,7 +409,7 @@ static int globexp2(const Char *ptr, const Char *pattern, glob_t *pglob, struct
 				qprintf("globexp2:", patbuf);
 #endif
 				rv = globexp1(patbuf, pglob, limitp);
-				if (rv && rv != GLOB_NOMATCH)
+				if (rv && rv != PHP_GLOB_NOMATCH)
 					return rv;
 
 				/* move after the comma, to the next string */
@@ -418,7 +429,7 @@ static int globexp2(const Char *ptr, const Char *pattern, glob_t *pglob, struct
 /*
  * expand tilde from the passwd file.
  */
-static const Char *globtilde(const Char *pattern, Char *patbuf, size_t patbuf_len, glob_t *pglob)
+static const Char *globtilde(const Char *pattern, Char *patbuf, size_t patbuf_len, php_glob_t *pglob)
 {
 #ifndef PHP_WIN32
 	struct passwd pwstore, *pwd = NULL;
@@ -428,7 +439,7 @@ static const Char *globtilde(const Char *pattern, Char *patbuf, size_t patbuf_le
 	const Char *p;
 	Char *b, *eb;
 
-	if (*pattern != TILDE || !(pglob->gl_flags & GLOB_TILDE))
+	if (*pattern != TILDE || !(pglob->gl_flags & PHP_GLOB_TILDE))
 		return pattern;
 
 	/* Copy up to the end of the string or / */
@@ -450,7 +461,11 @@ static const Char *globtilde(const Char *pattern, Char *patbuf, size_t patbuf_le
 		 * handle a plain ~ or ~/ by expanding $HOME
 		 * first and then trying the password file
 		 */
+#ifdef HAVE_ISSETUGID
 		if (issetugid() != 0 || (h = getenv("HOME")) == NULL) {
+#else
+		if ((h = getenv("HOME")) == NULL) {
+#endif
 			getpwuid_r(getuid(), &pwstore, pwbuf, sizeof(pwbuf),
 				&pwd);
 			if (pwd == NULL)
@@ -536,7 +551,7 @@ static int g_charclass(const Char **patternp, Char **bufnextp)
  * if things went well, nonzero if errors occurred.  It is not an error
  * to find no matches.
  */
-static int glob0(const Char *pattern, glob_t *pglob, struct glob_lim *limitp)
+static int glob0(const Char *pattern, php_glob_t *pglob, struct glob_lim *limitp)
 {
 	const Char *qpatnext;
 	int c, err;
@@ -575,8 +590,8 @@ static int glob0(const Char *pattern, glob_t *pglob, struct glob_lim *limitp)
 						c = *qpatnext++;
 					} while (c == LBRACKET && *qpatnext == ':');
 					if (err == -1 &&
-						!(pglob->gl_flags & GLOB_NOCHECK))
-						return GLOB_NOMATCH;
+						!(pglob->gl_flags & PHP_GLOB_NOCHECK))
+						return PHP_GLOB_NOMATCH;
 					if (c == RBRACKET)
 						break;
 				}
@@ -588,15 +603,15 @@ static int glob0(const Char *pattern, glob_t *pglob, struct glob_lim *limitp)
 					qpatnext += 2;
 				}
 			} while ((c = *qpatnext++) != RBRACKET);
-			pglob->gl_flags |= GLOB_MAGCHAR;
+			pglob->gl_flags |= PHP_GLOB_MAGCHAR;
 			*bufnext++ = M_END;
 			break;
 		case QUESTION:
-			pglob->gl_flags |= GLOB_MAGCHAR;
+			pglob->gl_flags |= PHP_GLOB_MAGCHAR;
 			*bufnext++ = M_ONE;
 			break;
 		case STAR:
-			pglob->gl_flags |= GLOB_MAGCHAR;
+			pglob->gl_flags |= PHP_GLOB_MAGCHAR;
 			/* collapse adjacent stars to one,
 			 * to avoid exponential behavior
 			 */
@@ -618,20 +633,20 @@ static int glob0(const Char *pattern, glob_t *pglob, struct glob_lim *limitp)
 
 	/*
 	 * If there was no match we are going to append the pattern
-	 * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified
+	 * if PHP_GLOB_NOCHECK was specified or if PHP_GLOB_NOMAGIC was specified
 	 * and the pattern did not contain any magic characters
-	 * GLOB_NOMAGIC is there just for compatibility with csh.
+	 * PHP_GLOB_NOMAGIC is there just for compatibility with csh.
 	 */
 	if (pglob->gl_pathc == oldpathc) {
-		if ((pglob->gl_flags & GLOB_NOCHECK) ||
-			((pglob->gl_flags & GLOB_NOMAGIC) &&
-			!(pglob->gl_flags & GLOB_MAGCHAR)))
+		if ((pglob->gl_flags & PHP_GLOB_NOCHECK) ||
+			((pglob->gl_flags & PHP_GLOB_NOMAGIC) &&
+			!(pglob->gl_flags & PHP_GLOB_MAGCHAR)))
 			return(globextend(pattern, pglob, limitp, NULL));
 		else
-			return(GLOB_NOMATCH);
+			return(PHP_GLOB_NOMATCH);
 	}
-	if (!(pglob->gl_flags & GLOB_NOSORT)) {
-		if ((pglob->gl_flags & GLOB_KEEPSTAT)) {
+	if (!(pglob->gl_flags & PHP_GLOB_NOSORT)) {
+		if ((pglob->gl_flags & PHP_GLOB_KEEPSTAT)) {
 			/* Keep the paths and stat info synced during sort */
 			struct glob_path_stat *path_stat;
 			size_t i;
@@ -639,7 +654,7 @@ static int glob0(const Char *pattern, glob_t *pglob, struct glob_lim *limitp)
 			size_t o = pglob->gl_offs + oldpathc;
 
 			if ((path_stat = calloc(n, sizeof(*path_stat))) == NULL)
-				return GLOB_NOSPACE;
+				return PHP_GLOB_NOSPACE;
 			for (i = 0; i < n; i++) {
 				path_stat[i].gps_path = pglob->gl_pathv[o + i];
 				path_stat[i].gps_stat = pglob->gl_statv[o + i];
@@ -672,7 +687,7 @@ static int compare_gps(const void *_p, const void *_q)
 	return(strcmp(p->gps_path, q->gps_path));
 }
 
-static int glob1(Char *pattern, Char *pattern_last, glob_t *pglob, struct glob_lim *limitp)
+static int glob1(Char *pattern, Char *pattern_last, php_glob_t *pglob, struct glob_lim *limitp)
 {
 	Char pathbuf[PATH_MAX];
 
@@ -689,7 +704,7 @@ static int glob1(Char *pattern, Char *pattern_last, glob_t *pglob, struct glob_l
  * of recursion for each segment in the pattern that contains one or more
  * meta characters.
  */
-static int glob2(Char *pathbuf, Char *pathbuf_last, Char *pathend, Char *pathend_last, Char *pattern, Char *pattern_last, glob_t *pglob, struct glob_lim *limitp)
+static int glob2(Char *pathbuf, Char *pathbuf_last, Char *pathend, Char *pathend_last, Char *pattern, Char *pattern_last, php_glob_t *pglob, struct glob_lim *limitp)
 {
 	zend_stat_t sb;
 	Char *p, *q;
@@ -703,17 +718,17 @@ static int glob2(Char *pathbuf, Char *pathbuf_last, Char *pathend, Char *pathend
 		if (*pattern == EOS) {		/* End of pattern? */
 			*pathend = EOS;
 
-			if ((pglob->gl_flags & GLOB_LIMIT) &&
-				limitp->glim_stat++ >= GLOB_LIMIT_STAT) {
+			if ((pglob->gl_flags & PHP_GLOB_LIMIT) &&
+				limitp->glim_stat++ >= PHP_GLOB_LIMIT_STAT) {
 				errno = 0;
 				*pathend++ = SEP;
 				*pathend = EOS;
-				return(GLOB_NOSPACE);
+				return(PHP_GLOB_NOSPACE);
 			}
 			if (g_lstat(pathbuf, &sb, pglob))
 				return(0);
 
-			if (((pglob->gl_flags & GLOB_MARK) &&
+			if (((pglob->gl_flags & PHP_GLOB_MARK) &&
 				pathend[-1] != SEP) && (S_ISDIR(sb.st_mode) ||
 				(S_ISLNK(sb.st_mode) &&
 				(g_stat(pathbuf, &sb, pglob) == 0) &&
@@ -755,7 +770,7 @@ static int glob2(Char *pathbuf, Char *pathbuf_last, Char *pathend, Char *pathend
 	/* NOTREACHED */
 }
 
-static int glob3(Char *pathbuf, Char *pathbuf_last, Char *pathend, Char *pathend_last, Char *pattern, Char *restpattern, Char *restpattern_last, glob_t *pglob, struct glob_lim *limitp)
+static int glob3(Char *pathbuf, Char *pathbuf_last, Char *pathend, Char *pathend_last, Char *pattern, Char *restpattern, Char *restpattern_last, php_glob_t *pglob, struct glob_lim *limitp)
 {
 	struct dirent *dp;
 	DIR *dirp;
@@ -779,10 +794,10 @@ static int glob3(Char *pathbuf, Char *pathbuf_last, Char *pathend, Char *pathend
 		/* TODO: don't call for ENOENT or ENOTDIR? */
 		if (pglob->gl_errfunc) {
 			if (g_Ctoc(pathbuf, buf, sizeof(buf)))
-				return(GLOB_ABORTED);
+				return(PHP_GLOB_ABORTED);
 			if (pglob->gl_errfunc(buf, errno) ||
-				pglob->gl_flags & GLOB_ERR)
-				return(GLOB_ABORTED);
+				pglob->gl_flags & PHP_GLOB_ERR)
+				return(PHP_GLOB_ABORTED);
 		}
 		return(0);
 	}
@@ -790,7 +805,7 @@ static int glob3(Char *pathbuf, Char *pathbuf_last, Char *pathend, Char *pathend
 	err = 0;
 
 	/* Search directory for matching names. */
-	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
+	if (pglob->gl_flags & PHP_GLOB_ALTDIRFUNC)
 		readdirfunc = pglob->gl_readdir;
 	else
 		readdirfunc = (struct dirent *(*)(void *))readdir;
@@ -798,12 +813,12 @@ static int glob3(Char *pathbuf, Char *pathbuf_last, Char *pathend, Char *pathend
 		uint8_t *sc;
 		Char *dc;
 
-		if ((pglob->gl_flags & GLOB_LIMIT) &&
-			limitp->glim_readdir++ >= GLOB_LIMIT_READDIR) {
+		if ((pglob->gl_flags & PHP_GLOB_LIMIT) &&
+			limitp->glim_readdir++ >= PHP_GLOB_LIMIT_READDIR) {
 			errno = 0;
 			*pathend++ = SEP;
 			*pathend = EOS;
-			err = GLOB_NOSPACE;
+			err = PHP_GLOB_NOSPACE;
 			break;
 		}
 
@@ -830,7 +845,7 @@ static int glob3(Char *pathbuf, Char *pathbuf_last, Char *pathend, Char *pathend
 			break;
 	}
 
-	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
+	if (pglob->gl_flags & PHP_GLOB_ALTDIRFUNC)
 		(*pglob->gl_closedir)(dirp);
 	else
 		closedir(dirp);
@@ -839,7 +854,7 @@ static int glob3(Char *pathbuf, Char *pathbuf_last, Char *pathend, Char *pathend
 
 
 /*
- * Extend the gl_pathv member of a glob_t structure to accommodate a new item,
+ * Extend the gl_pathv member of a php_glob_t structure to accommodate a new item,
  * add the new item, and update gl_pathc.
  *
  * This assumes the BSD realloc, which only copies the block when its size
@@ -848,11 +863,11 @@ static int glob3(Char *pathbuf, Char *pathbuf_last, Char *pathend, Char *pathend
  *
  * Return 0 if new item added, error code if memory couldn't be allocated.
  *
- * Invariant of the glob_t structure:
+ * Invariant of the php_glob_t structure:
  *	Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and
  *	gl_pathv points to (gl_offs + gl_pathc + 1) items.
  */
-static int globextend(const Char *path, glob_t *pglob, struct glob_lim *limitp, zend_stat_t *sb)
+static int globextend(const Char *path, php_glob_t *pglob, struct glob_lim *limitp, zend_stat_t *sb)
 {
 	char **pathv;
 	size_t i, newn, len;
@@ -870,7 +885,7 @@ static int globextend(const Char *path, glob_t *pglob, struct glob_lim *limitp,
 		for (i = pglob->gl_offs; i < newn - 2; i++) {
 			if (pglob->gl_pathv && pglob->gl_pathv[i])
 				free(pglob->gl_pathv[i]);
-			if ((pglob->gl_flags & GLOB_KEEPSTAT) != 0 &&
+			if ((pglob->gl_flags & PHP_GLOB_KEEPSTAT) != 0 &&
 				pglob->gl_pathv && pglob->gl_pathv[i])
 				free(pglob->gl_statv[i]);
 		}
@@ -878,7 +893,7 @@ static int globextend(const Char *path, glob_t *pglob, struct glob_lim *limitp,
 		pglob->gl_pathv = NULL;
 		free(pglob->gl_statv);
 		pglob->gl_statv = NULL;
-		return(GLOB_NOSPACE);
+		return(PHP_GLOB_NOSPACE);
 	}
 
 	pathv = reallocarray(pglob->gl_pathv, newn, sizeof(*pathv));
@@ -892,7 +907,7 @@ static int globextend(const Char *path, glob_t *pglob, struct glob_lim *limitp,
 	}
 	pglob->gl_pathv = pathv;
 
-	if ((pglob->gl_flags & GLOB_KEEPSTAT) != 0) {
+	if ((pglob->gl_flags & PHP_GLOB_KEEPSTAT) != 0) {
 		statv = reallocarray(pglob->gl_statv, newn, sizeof(*statv));
 		if (statv == NULL)
 			goto nospace;
@@ -907,10 +922,10 @@ static int globextend(const Char *path, glob_t *pglob, struct glob_lim *limitp,
 			statv[pglob->gl_offs + pglob->gl_pathc] = NULL;
 		else {
 			limitp->glim_malloc += sizeof(**statv);
-			if ((pglob->gl_flags & GLOB_LIMIT) &&
-				limitp->glim_malloc >= GLOB_LIMIT_MALLOC) {
+			if ((pglob->gl_flags & PHP_GLOB_LIMIT) &&
+				limitp->glim_malloc >= PHP_GLOB_LIMIT_MALLOC) {
 				errno = 0;
-				return(GLOB_NOSPACE);
+				return(PHP_GLOB_NOSPACE);
 			}
 			if ((statv[pglob->gl_offs + pglob->gl_pathc] =
 				malloc(sizeof(**statv))) == NULL)
@@ -928,20 +943,20 @@ static int globextend(const Char *path, glob_t *pglob, struct glob_lim *limitp,
 	if ((copy = malloc(len)) != NULL) {
 		if (g_Ctoc(path, copy, len)) {
 			free(copy);
-			return(GLOB_NOSPACE);
+			return(PHP_GLOB_NOSPACE);
 		}
 		pathv[pglob->gl_offs + pglob->gl_pathc++] = copy;
 	}
 	pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
 
-	if ((pglob->gl_flags & GLOB_LIMIT) &&
+	if ((pglob->gl_flags & PHP_GLOB_LIMIT) &&
 		(newn * sizeof(*pathv)) + limitp->glim_malloc >
-		GLOB_LIMIT_MALLOC) {
+		PHP_GLOB_LIMIT_MALLOC) {
 		errno = 0;
-		return(GLOB_NOSPACE);
+		return(PHP_GLOB_NOSPACE);
 	}
  copy_error:
-	return(copy == NULL ? GLOB_NOSPACE : 0);
+	return(copy == NULL ? PHP_GLOB_NOSPACE : 0);
 }
 
 
@@ -1023,8 +1038,8 @@ static int match(Char *name, Char *pat, Char *patend)
 	return(0);
 }
 
-/* Free allocated data belonging to a glob_t structure. */
-PHPAPI void globfree(glob_t *pglob)
+/* Free allocated data belonging to a php_glob_t structure. */
+PHPAPI void php_globfree(php_glob_t *pglob)
 {
 	size_t i;
 	char **pp;
@@ -1045,7 +1060,7 @@ PHPAPI void globfree(glob_t *pglob)
 	}
 }
 
-static DIR *g_opendir(Char *str, glob_t *pglob)
+static DIR *g_opendir(Char *str, php_glob_t *pglob)
 {
 	char buf[PATH_MAX];
 
@@ -1056,30 +1071,30 @@ static DIR *g_opendir(Char *str, glob_t *pglob)
 			return(NULL);
 	}
 
-	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
+	if (pglob->gl_flags & PHP_GLOB_ALTDIRFUNC)
 		return((*pglob->gl_opendir)(buf));
 
 	return(opendir(buf));
 }
 
-static int g_lstat(Char *fn, zend_stat_t *sb, glob_t *pglob)
+static int g_lstat(Char *fn, zend_stat_t *sb, php_glob_t *pglob)
 {
 	char buf[PATH_MAX];
 
 	if (g_Ctoc(fn, buf, sizeof(buf)))
 		return(-1);
-	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
+	if (pglob->gl_flags & PHP_GLOB_ALTDIRFUNC)
 		return((*pglob->gl_lstat)(buf, sb));
 	return(php_sys_lstat(buf, sb));
 }
 
-static int g_stat(Char *fn, zend_stat_t *sb, glob_t *pglob)
+static int g_stat(Char *fn, zend_stat_t *sb, php_glob_t *pglob)
 {
 	char buf[PATH_MAX];
 
 	if (g_Ctoc(fn, buf, sizeof(buf)))
 		return(-1);
-	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
+	if (pglob->gl_flags & PHP_GLOB_ALTDIRFUNC)
 		return((*pglob->gl_stat)(buf, sb));
 	return(php_sys_stat(buf, sb));
 }
@@ -1120,3 +1135,5 @@ static void qprintf(const char *str, Char *s)
 	(void)printf("\n");
 }
 #endif
+
+#endif /* defined(HAVE_GLOB) */
diff --git a/main/php_glob.h b/main/php_glob.h
new file mode 100644
index 0000000000000..853a8b31f5ce0
--- /dev/null
+++ b/main/php_glob.h
@@ -0,0 +1,184 @@
+/*	$OpenBSD: glob.h,v 1.14 2019/02/04 16:45:40 millert Exp $	*/
+/*	$NetBSD: glob.h,v 1.5 1994/10/26 00:55:56 cgd Exp $	*/
+
+/*
+ * Copyright (c) 1989, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Guido van Rossum.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)glob.h	8.1 (Berkeley) 6/2/93
+ */
+
+#ifdef PHP_WIN32
+#include "config.w32.h"
+#else
+#include <php_config.h>
+#endif
+
+#ifndef _PHP_GLOB_H_
+#define	_PHP_GLOB_H_
+
+#if defined(HAVE_GLOB) && defined(PHP_SYSTEM_GLOB)
+#include <glob.h>
+
+#ifdef GLOB_APPEND
+#define PHP_GLOB_APPEND GLOB_APPEND
+#endif
+#ifdef GLOB_DOOFFS
+#define PHP_GLOB_DOOFFS GLOB_DOOFFS
+#endif
+#ifdef GLOB_ERR
+#define PHP_GLOB_ERR GLOB_ERR
+#endif
+#ifdef GLOB_MARK
+#define PHP_GLOB_MARK GLOB_MARK
+#endif
+#ifdef GLOB_NOCHECK
+#define PHP_GLOB_NOCHECK GLOB_NOCHECK
+#endif
+#ifdef GLOB_NOSORT
+#define PHP_GLOB_NOSORT GLOB_NOSORT
+#endif
+#ifdef GLOB_NOESCAPE
+#define PHP_GLOB_NOESCAPE GLOB_NOESCAPE
+#endif
+#ifdef GLOB_NOSPACE
+#define PHP_GLOB_NOSPACE GLOB_NOSPACE
+#endif
+#ifdef GLOB_ABORTED
+#define PHP_GLOB_ABORTED GLOB_ABORTED
+#endif
+#ifdef GLOB_NOMATCH
+#define PHP_GLOB_NOMATCH GLOB_NOMATCH
+#endif
+#ifdef GLOB_NOSYS
+#define PHP_GLOB_NOSYS GLOB_NOSYS
+#endif
+#ifdef GLOB_ALTDIRFUNC
+#define PHP_GLOB_ALTDIRFUNC GLOB_ALTDIRFUNC
+#endif
+#ifdef GLOB_BRACE
+#define PHP_GLOB_BRACE GLOB_BRACE
+#endif
+#ifdef GLOB_MAGCHAR
+#define PHP_GLOB_MAGCHAR GLOB_MAGCHAR
+#endif
+#ifdef GLOB_NOMAGIC
+#define PHP_GLOB_NOMAGIC GLOB_NOMAGIC
+#endif
+#ifdef GLOB_QUOTE
+#define PHP_GLOB_QUOTE GLOB_QUOTE
+#endif
+#ifdef GLOB_TILDE
+#define PHP_GLOB_TILDE GLOB_TILDE
+#endif
+#ifdef GLOB_LIMIT
+#define PHP_GLOB_LIMIT GLOB_LIMIT
+#endif
+#ifdef GLOB_KEEPSTAT
+#define PHP_GLOB_KEEPSTAT GLOB_KEEPSTAT
+#endif
+
+#define php_glob_t glob_t
+#define php_glob glob
+#define php_globfree globfree
+#else
+
+#include "php.h"
+
+#ifndef PHP_WIN32
+# include <sys/cdefs.h>
+#endif
+
+#include "Zend/zend_stream.h"
+
+typedef struct {
+	size_t gl_pathc;	/* Count of total paths so far. */
+	size_t gl_matchc;	/* Count of paths matching pattern. */
+	size_t gl_offs;		/* Reserved at beginning of gl_pathv. */
+	int gl_flags;		/* Copy of flags parameter to glob. */
+	char **gl_pathv;	/* List of paths matching pattern. */
+	zend_stat_t **gl_statv;	/* Stat entries corresponding to gl_pathv */
+				/* Copy of errfunc parameter to glob. */
+	int (*gl_errfunc)(const char *, int);
+
+	/*
+	 * Alternate filesystem access methods for glob; replacement
+	 * versions of closedir(3), readdir(3), opendir(3), stat(2)
+	 * and lstat(2).
+	 */
+	void (*gl_closedir)(void *);
+	struct dirent *(*gl_readdir)(void *);
+	void *(*gl_opendir)(const char *);
+	int (*gl_lstat)(const char *, zend_stat_t *);
+	int (*gl_stat)(const char *, zend_stat_t *);
+} php_glob_t;
+
+#define	PHP_GLOB_APPEND	0x0001	/* Append to output from previous call. */
+#define	PHP_GLOB_DOOFFS	0x0002	/* Use gl_offs. */
+#define	PHP_GLOB_ERR	0x0004	/* Return on error. */
+#define	PHP_GLOB_MARK	0x0008	/* Append / to matching directories. */
+#define	PHP_GLOB_NOCHECK	0x0010	/* Return pattern itself if nothing matches. */
+#define	PHP_GLOB_NOSORT	0x0020	/* Don't sort. */
+#define	PHP_GLOB_NOESCAPE	0x1000	/* Disable backslash escaping. */
+
+#define	PHP_GLOB_NOSPACE	(-1)	/* Malloc call failed. */
+#define	PHP_GLOB_ABORTED	(-2)	/* Unignored error. */
+#define	PHP_GLOB_NOMATCH	(-3)	/* No match and PHP_GLOB_NOCHECK not set. */
+#define	PHP_GLOB_NOSYS	(-4)	/* Function not supported. */
+
+#define	PHP_GLOB_ALTDIRFUNC	0x0040	/* Use alternately specified directory funcs. */
+#define	PHP_GLOB_BRACE	0x0080	/* Expand braces ala csh. */
+#define	PHP_GLOB_MAGCHAR	0x0100	/* Pattern had globbing characters. */
+#define	PHP_GLOB_NOMAGIC	0x0200	/* PHP_GLOB_NOCHECK without magic chars (csh). */
+#define	PHP_GLOB_QUOTE	0x0400	/* Quote special chars with \. */
+#define	PHP_GLOB_TILDE	0x0800	/* Expand tilde names from the passwd file. */
+#define PHP_GLOB_LIMIT	0x2000	/* Limit pattern match output to ARG_MAX */
+#define	PHP_GLOB_KEEPSTAT	0x4000	/* Retain stat data for paths in gl_statv. */
+
+BEGIN_EXTERN_C()
+PHPAPI int	php_glob(const char *__restrict, int, int (*)(const char *, int),
+	    php_glob_t *__restrict);
+PHPAPI void	php_globfree(php_glob_t *);
+END_EXTERN_C()
+
+#endif /* defined(HAVE_GLOB) */
+
+/* These were copied from dir and zip */
+
+#ifndef PHP_GLOB_ONLYDIR
+#define PHP_GLOB_ONLYDIR (1<<30)
+#define PHP_GLOB_FLAGMASK (~PHP_GLOB_ONLYDIR)
+#else
+#define PHP_GLOB_FLAGMASK (~0)
+#endif
+
+#define PHP_GLOB_AVAILABLE_FLAGS (0 | PHP_GLOB_BRACE | PHP_GLOB_MARK | PHP_GLOB_NOSORT | PHP_GLOB_NOCHECK | PHP_GLOB_NOESCAPE | PHP_GLOB_ERR | PHP_GLOB_ONLYDIR)
+
+#endif /* !_GLOB_H_ */
diff --git a/main/streams/glob_wrapper.c b/main/streams/glob_wrapper.c
index 8772850f784f3..fb056ce889fa4 100644
--- a/main/streams/glob_wrapper.c
+++ b/main/streams/glob_wrapper.c
@@ -17,24 +17,10 @@
 #include "php.h"
 #include "php_streams_int.h"
 
-#ifdef HAVE_GLOB
-# ifndef PHP_WIN32
-#  include <glob.h>
-# else
-#  include "win32/glob.h"
-# endif
-#endif
-
-#ifdef HAVE_GLOB
-#ifndef GLOB_ONLYDIR
-#define GLOB_ONLYDIR (1<<30)
-#define GLOB_FLAGMASK (~GLOB_ONLYDIR)
-#else
-#define GLOB_FLAGMASK (~0)
-#endif
+#include "php_glob.h"
 
 typedef struct {
-	glob_t   glob;
+	php_glob_t glob;
 	size_t   index;
 	int      flags;
 	char     *path;
@@ -147,7 +133,7 @@ static ssize_t php_glob_stream_read(php_stream *stream, char *buf, size_t count)
 		if (pglob->index < (size_t) glob_result_count) {
 			index = pglob->open_basedir_used && pglob->open_basedir_indexmap ?
 					pglob->open_basedir_indexmap[pglob->index] : pglob->index;
-			php_glob_stream_path_split(pglob, pglob->glob.gl_pathv[index], pglob->flags & GLOB_APPEND, &path);
+			php_glob_stream_path_split(pglob, pglob->glob.gl_pathv[index], pglob->flags & PHP_GLOB_APPEND, &path);
 			++pglob->index;
 			PHP_STRLCPY(ent->d_name, path, sizeof(ent->d_name), strlen(path));
 			ent->d_type = DT_UNKNOWN;
@@ -170,7 +156,7 @@ static int php_glob_stream_close(php_stream *stream, int close_handle)  /* {{{ *
 
 	if (pglob) {
 		pglob->index = 0;
-		globfree(&pglob->glob);
+		php_globfree(&pglob->glob);
 		if (pglob->path) {
 			efree(pglob->path);
 		}
@@ -250,9 +236,9 @@ static php_stream *php_glob_stream_opener(php_stream_wrapper *wrapper, const cha
 
 	pglob = ecalloc(1, sizeof(*pglob));
 
-	if (0 != (ret = glob(pattern, pglob->flags & GLOB_FLAGMASK, NULL, &pglob->glob))) {
-#ifdef GLOB_NOMATCH
-		if (GLOB_NOMATCH != ret)
+	if (0 != (ret = php_glob(pattern, pglob->flags & PHP_GLOB_FLAGMASK, NULL, &pglob->glob))) {
+#ifdef PHP_GLOB_NOMATCH
+		if (PHP_GLOB_NOMATCH != ret)
 #endif
 		{
 			efree(pglob);
@@ -302,7 +288,7 @@ static php_stream *php_glob_stream_opener(php_stream_wrapper *wrapper, const cha
 	pglob->pattern_len = strlen(pos);
 	pglob->pattern = estrndup(pos, pglob->pattern_len);
 
-	pglob->flags |= GLOB_APPEND;
+	pglob->flags |= PHP_GLOB_APPEND;
 
 	if (pglob->glob.gl_pathc) {
 		php_glob_stream_path_split(pglob, pglob->glob.gl_pathv[0], 1, &tmp);
@@ -333,4 +319,3 @@ const php_stream_wrapper  php_glob_stream_wrapper = {
 	NULL,
 	0
 };
-#endif /* HAVE_GLOB */
diff --git a/main/streams/plain_wrapper.c b/main/streams/plain_wrapper.c
index 9396d68ecea80..a8fd70b8d6ac2 100644
--- a/main/streams/plain_wrapper.c
+++ b/main/streams/plain_wrapper.c
@@ -1088,11 +1088,9 @@ static php_stream *php_plain_files_dir_opener(php_stream_wrapper *wrapper, const
 	DIR *dir = NULL;
 	php_stream *stream = NULL;
 
-#ifdef HAVE_GLOB
 	if (options & STREAM_USE_GLOB_DIR_OPEN) {
 		return php_glob_stream_wrapper.wops->dir_opener((php_stream_wrapper*)&php_glob_stream_wrapper, path, mode, options, opened_path, context STREAMS_REL_CC);
 	}
-#endif
 
 	if (((options & STREAM_DISABLE_OPEN_BASEDIR) == 0) && php_check_open_basedir(path)) {
 		return NULL;
diff --git a/sapi/fpm/fpm/fpm_conf.c b/sapi/fpm/fpm/fpm_conf.c
index ac4343bbf889e..e18cfebda08f5 100644
--- a/sapi/fpm/fpm/fpm_conf.c
+++ b/sapi/fpm/fpm/fpm_conf.c
@@ -10,9 +10,6 @@
 #include <stddef.h>
 #include <string.h>
 #include <inttypes.h>
-#ifdef HAVE_GLOB
-# include <glob.h>
-#endif
 
 #include <stdio.h>
 #include <unistd.h>
@@ -22,6 +19,7 @@
 #include "zend_globals.h"
 #include "zend_stream.h"
 #include "php_syslog.h"
+#include "php_glob.h"
 
 #include "fpm.h"
 #include "fpm_conf.h"
@@ -1387,26 +1385,23 @@ static void fpm_conf_ini_parser_include(char *inc, void *arg) /* {{{ */
 {
 	char *filename;
 	int *error = (int *)arg;
-#ifdef HAVE_GLOB
-	glob_t g;
-#endif
+	php_glob_t g;
 	size_t i;
 
 	if (!inc || !arg) return;
 	if (*error) return; /* We got already an error. Switch to the end. */
 	spprintf(&filename, 0, "%s", ini_filename);
 
-#ifdef HAVE_GLOB
 	{
 		g.gl_offs = 0;
-		if ((i = glob(inc, GLOB_ERR | GLOB_MARK, NULL, &g)) != 0) {
-#ifdef GLOB_NOMATCH
-			if (i == GLOB_NOMATCH) {
+		if ((i = php_glob(inc, PHP_GLOB_ERR | PHP_GLOB_MARK, NULL, &g)) != 0) {
+#ifdef PHP_GLOB_NOMATCH
+			if (i == PHP_GLOB_NOMATCH) {
 				zlog(ZLOG_WARNING, "Nothing matches the include pattern '%s' from %s at line %d.", inc, filename, ini_lineno);
 				efree(filename);
 				return;
 			}
-#endif /* GLOB_NOMATCH */
+#endif /* PHP_GLOB_NOMATCH */
 			zlog(ZLOG_ERROR, "Unable to globalize '%s' (ret=%zd) from %s at line %d.", inc, i, filename, ini_lineno);
 			*error = 1;
 			efree(filename);
@@ -1424,16 +1419,8 @@ static void fpm_conf_ini_parser_include(char *inc, void *arg) /* {{{ */
 				return;
 			}
 		}
-		globfree(&g);
-	}
-#else /* HAVE_GLOB */
-	if (0 > fpm_conf_load_ini_file(inc)) {
-		zlog(ZLOG_ERROR, "Unable to include %s from %s at line %d", inc, filename, ini_lineno);
-		*error = 1;
-		efree(filename);
-		return;
+		php_globfree(&g);
 	}
-#endif /* HAVE_GLOB */
 
 	efree(filename);
 }
diff --git a/win32/build/config.w32 b/win32/build/config.w32
index f82ed73efe3bd..63d17af09e44f 100644
--- a/win32/build/config.w32
+++ b/win32/build/config.w32
@@ -284,7 +284,7 @@ if (VS_TOOLSET && VCVERS >= 1914) {
 //AC_DEFINE('ZEND_DVAL_TO_LVAL_CAST_OK', 1);
 
 ADD_SOURCES("main", "main.c snprintf.c spprintf.c getopt.c fopen_wrappers.c \
-	php_ini_builder.c \
+	php_ini_builder.c php_glob.c \
 	php_scandir.c php_ini.c SAPI.c rfc1867.c php_content_types.c strlcpy.c \
 	strlcat.c reentrancy.c php_variables.c php_ticks.c network.c \
 	php_open_temporary_file.c output.c internal_functions.c \
@@ -305,7 +305,7 @@ if (VS_TOOLSET && VCVERS >= 1914) {
 	ADD_FLAG("CFLAGS_BD_MAIN_STREAMS", "/d2FuncCache1");
 }
 
-ADD_SOURCES("win32", "dllmain.c glob.c readdir.c \
+ADD_SOURCES("win32", "dllmain.c readdir.c \
 	registry.c select.c sendmail.c time.c winutil.c wsyslog.c globals.c \
 	getrusage.c ftok.c ioutil.c codepage.c nice.c \
 	fnmatch.c sockets.c console.c signal.c");
diff --git a/win32/build/config.w32.h.in b/win32/build/config.w32.h.in
index c3d2fba966bc2..40a4264cf396f 100644
--- a/win32/build/config.w32.h.in
+++ b/win32/build/config.w32.h.in
@@ -92,7 +92,6 @@
 #endif
 #define SIZEOF_OFF_T 4
 #define HAVE_FNMATCH
-#define HAVE_GLOB
 #define PHP_SHLIB_SUFFIX "dll"
 #define PHP_SHLIB_EXT_PREFIX "php_"
 
diff --git a/win32/glob.h b/win32/glob.h
deleted file mode 100644
index 0975c507388d5..0000000000000
--- a/win32/glob.h
+++ /dev/null
@@ -1,100 +0,0 @@
-/*	$OpenBSD: glob.h,v 1.14 2019/02/04 16:45:40 millert Exp $	*/
-/*	$NetBSD: glob.h,v 1.5 1994/10/26 00:55:56 cgd Exp $	*/
-
-/*
- * Copyright (c) 1989, 1993
- *	The Regents of the University of California.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Guido van Rossum.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- *	@(#)glob.h	8.1 (Berkeley) 6/2/93
- */
-
-#ifndef _GLOB_H_
-#define	_GLOB_H_
-
-#ifndef PHP_WIN32
-# include <sys/cdefs.h>
-#endif
-
-#include "Zend/zend_stream.h"
-
-typedef struct {
-	size_t gl_pathc;	/* Count of total paths so far. */
-	size_t gl_matchc;	/* Count of paths matching pattern. */
-	size_t gl_offs;		/* Reserved at beginning of gl_pathv. */
-	int gl_flags;		/* Copy of flags parameter to glob. */
-	char **gl_pathv;	/* List of paths matching pattern. */
-	zend_stat_t **gl_statv;	/* Stat entries corresponding to gl_pathv */
-				/* Copy of errfunc parameter to glob. */
-	int (*gl_errfunc)(const char *, int);
-
-	/*
-	 * Alternate filesystem access methods for glob; replacement
-	 * versions of closedir(3), readdir(3), opendir(3), stat(2)
-	 * and lstat(2).
-	 */
-	void (*gl_closedir)(void *);
-	struct dirent *(*gl_readdir)(void *);
-	void *(*gl_opendir)(const char *);
-	int (*gl_lstat)(const char *, zend_stat_t *);
-	int (*gl_stat)(const char *, zend_stat_t *);
-} glob_t;
-
-#define	GLOB_APPEND	0x0001	/* Append to output from previous call. */
-#define	GLOB_DOOFFS	0x0002	/* Use gl_offs. */
-#define	GLOB_ERR	0x0004	/* Return on error. */
-#define	GLOB_MARK	0x0008	/* Append / to matching directories. */
-#define	GLOB_NOCHECK	0x0010	/* Return pattern itself if nothing matches. */
-#define	GLOB_NOSORT	0x0020	/* Don't sort. */
-#define	GLOB_NOESCAPE	0x1000	/* Disable backslash escaping. */
-
-#define	GLOB_NOSPACE	(-1)	/* Malloc call failed. */
-#define	GLOB_ABORTED	(-2)	/* Unignored error. */
-#define	GLOB_NOMATCH	(-3)	/* No match and GLOB_NOCHECK not set. */
-#define	GLOB_NOSYS	(-4)	/* Function not supported. */
-
-#ifndef _POSIX_SOURCE
-#define	GLOB_ALTDIRFUNC	0x0040	/* Use alternately specified directory funcs. */
-#define	GLOB_BRACE	0x0080	/* Expand braces ala csh. */
-#define	GLOB_MAGCHAR	0x0100	/* Pattern had globbing characters. */
-#define	GLOB_NOMAGIC	0x0200	/* GLOB_NOCHECK without magic chars (csh). */
-#define	GLOB_QUOTE	0x0400	/* Quote special chars with \. */
-#define	GLOB_TILDE	0x0800	/* Expand tilde names from the passwd file. */
-#define GLOB_LIMIT	0x2000	/* Limit pattern match output to ARG_MAX */
-#define	GLOB_KEEPSTAT	0x4000	/* Retain stat data for paths in gl_statv. */
-#define GLOB_ABEND	GLOB_ABORTED /* backward compatibility */
-#endif
-
-BEGIN_EXTERN_C()
-PHPAPI int	glob(const char *__restrict, int, int (*)(const char *, int),
-	    glob_t *__restrict);
-PHPAPI void	globfree(glob_t *);
-END_EXTERN_C()
-
-#endif /* !_GLOB_H_ */