Commit 1b204626c5e for php.net
commit 1b204626c5eb9dc6b15cb4d156cc14a2b633c7f9
Author: Gina Peter Banyard <girgias@php.net>
Date: Sun Jul 19 18:48:03 2026 +0100
main: convert doc_root global to zend_string*
This remove a strlen() computation.
While at it clarify path concatenation code by using the zend_string_concat{2|3} APIs rather than a memcpy and strncpy calls
diff --git a/main/fopen_wrappers.c b/main/fopen_wrappers.c
index c0f88ad3b5b..562cf1c63b9 100644
--- a/main/fopen_wrappers.c
+++ b/main/fopen_wrappers.c
@@ -359,7 +359,6 @@ PHPAPI int php_fopen_primary_script(zend_file_handle *file_handle)
char *path_info;
zend_string *filename = NULL;
zend_string *resolved_path = NULL;
- size_t length;
bool orig_display_errors;
memset(file_handle, 0, sizeof(zend_file_handle));
@@ -372,7 +371,7 @@ PHPAPI int php_fopen_primary_script(zend_file_handle *file_handle)
if (s) { /* if there is no path name after the file, do not bother */
char user[32]; /* to try open the directory */
- length = s - (path_info + 2);
+ size_t length = s - (path_info + 2);
if (length > sizeof(user) - 1) {
length = sizeof(user) - 1;
}
@@ -421,19 +420,37 @@ PHPAPI int php_fopen_primary_script(zend_file_handle *file_handle)
}
} else
#endif
- if (PG(doc_root) && path_info && (length = strlen(PG(doc_root))) &&
- IS_ABSOLUTE_PATH(PG(doc_root), length)) {
- size_t path_len = strlen(path_info);
- filename = zend_string_alloc(length + path_len + 2, 0);
- memcpy(ZSTR_VAL(filename), PG(doc_root), length);
- if (!IS_SLASH(ZSTR_VAL(filename)[length - 1])) { /* length is never 0 */
- ZSTR_VAL(filename)[length++] = PHP_DIR_SEPARATOR;
- }
- if (IS_SLASH(path_info[0])) {
- length--;
- }
- strncpy(ZSTR_VAL(filename) + length, path_info, path_len + 1);
- ZSTR_LEN(filename) = length + path_len;
+ if (PG(doc_root) && path_info && IS_ABSOLUTE_PATH(ZSTR_VAL(PG(doc_root)), ZSTR_LEN(PG(doc_root)))) {
+ const size_t path_len = strlen(path_info);
+
+ /* We need to concatenate two paths together, there are 3 situations:
+ * - No trailing slash AND no leading slash
+ * - Trailing slash AND leading slash
+ * - Either a trailing slash OR a leading slash
+ * In the first case we need to add a slash, in the second one we need to skip the leading slash,
+ * and in the third we can just concatenate them together */
+ const unsigned int nb_slashes = IS_SLASH(ZSTR_VAL(PG(doc_root))[ZSTR_LEN(PG(doc_root)) - 1]) + IS_SLASH(path_info[0]);
+ switch (nb_slashes) {
+ case 0:
+ filename = zend_string_concat3(
+ ZSTR_VAL(PG(doc_root)), ZSTR_LEN(PG(doc_root)),
+ ZEND_STRL("/"),
+ path_info, path_len
+ );
+ break;
+ case 1:
+ filename = zend_string_concat2(
+ ZSTR_VAL(PG(doc_root)), ZSTR_LEN(PG(doc_root)),
+ path_info, path_len
+ );
+ break;
+ case 2:
+ filename = zend_string_concat2(
+ ZSTR_VAL(PG(doc_root)), ZSTR_LEN(PG(doc_root)),
+ path_info + 1, path_len -1
+ );
+ break;
+ }
} else if (SG(request_info).path_translated) {
filename = zend_string_init(SG(request_info).path_translated,
strlen(SG(request_info).path_translated), 0);
diff --git a/main/main.c b/main/main.c
index 3c079cb7fd7..5d26de4edc5 100644
--- a/main/main.c
+++ b/main/main.c
@@ -830,7 +830,7 @@ PHP_INI_BEGIN()
STD_PHP_INI_ENTRY("auto_append_file", NULL, PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateString, auto_append_file, php_core_globals, core_globals)
STD_PHP_INI_ENTRY("auto_prepend_file", NULL, PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateString, auto_prepend_file, php_core_globals, core_globals)
- STD_PHP_INI_ENTRY("doc_root", NULL, PHP_INI_SYSTEM, OnUpdateStringUnempty, doc_root, php_core_globals, core_globals)
+ STD_PHP_INI_ENTRY("doc_root", NULL, PHP_INI_SYSTEM, OnUpdateStrNotEmpty, doc_root, php_core_globals, core_globals)
STD_PHP_INI_ENTRY("default_charset", PHP_DEFAULT_CHARSET, PHP_INI_ALL, OnUpdateDefaultCharset, default_charset, sapi_globals_struct, sapi_globals)
STD_PHP_INI_ENTRY("default_mimetype", SAPI_DEFAULT_MIMETYPE, PHP_INI_ALL, OnUpdateDefaultMimeTye, default_mimetype, sapi_globals_struct, sapi_globals)
STD_PHP_INI_ENTRY("internal_encoding", NULL, PHP_INI_ALL, OnUpdateInternalEncoding, internal_encoding, php_core_globals, core_globals)
diff --git a/main/php_globals.h b/main/php_globals.h
index 333daab69ff..74639ffe0d4 100644
--- a/main/php_globals.h
+++ b/main/php_globals.h
@@ -76,7 +76,7 @@ struct _php_core_globals {
char *error_log;
- char *doc_root;
+ zend_string *doc_root;
char *user_dir;
char *include_path;
char *open_basedir;
diff --git a/sapi/cgi/cgi_main.c b/sapi/cgi/cgi_main.c
index 841f45b207a..a79eada2728 100644
--- a/sapi/cgi/cgi_main.c
+++ b/sapi/cgi/cgi_main.c
@@ -1221,7 +1221,7 @@ static void init_request_info(fcgi_request *request)
size_t script_path_translated_len;
if (!env_document_root && PG(doc_root)) {
- env_document_root = CGI_PUTENV("DOCUMENT_ROOT", PG(doc_root));
+ env_document_root = CGI_PUTENV("DOCUMENT_ROOT", ZSTR_VAL(PG(doc_root)));
/* fix docroot */
TRANSLATE_SLASHES(env_document_root);
}
diff --git a/sapi/fpm/fpm/fpm_main.c b/sapi/fpm/fpm/fpm_main.c
index 9b7cbcf16f0..655d66ce5f0 100644
--- a/sapi/fpm/fpm/fpm_main.c
+++ b/sapi/fpm/fpm/fpm_main.c
@@ -1078,7 +1078,7 @@ static void init_request_info(void)
int script_path_translated_len;
if (!env_document_root && PG(doc_root)) {
- env_document_root = FCGI_PUTENV(request, "DOCUMENT_ROOT", PG(doc_root));
+ env_document_root = FCGI_PUTENV(request, "DOCUMENT_ROOT", ZSTR_VAL(PG(doc_root)));
}
if (!apache_was_here && env_path_translated != NULL && env_redirect_url != NULL &&