Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions UPGRADING
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,9 @@ PHP 8.7 UPGRADE NOTES
========================================

- Standard:
. Improved performance of fgetcsv(), str_getcsv(), escapeshellarg() and
escapeshellcmd() in locales where ASCII characters are single bytes
(C, UTF-8 and single-byte locales).
. Improved performance of strcspn() and strpbrk() when searching longer strings
with a single-byte character mask.
. Improved performance of array_chunk() when not preserving keys.
Expand Down
3 changes: 3 additions & 0 deletions UPGRADING.INTERNALS
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@ PHP 8.7 INTERNALS UPGRADE NOTES
- Standard:
. php_explode() now takes a HashTable* instead of a zval* to store the
resulting parts. It already expected the zval* to be IS_ARRAY.
. php_mblen() and php_mb_reset() are inline functions. php_mb_reset() must be
called before the first php_mblen() of a string; the conversion state is
kept in BG(mblen_state) in NTS builds too.

========================
4. OpCode changes
Expand Down
5 changes: 2 additions & 3 deletions ext/standard/basic_functions.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,10 +98,9 @@ typedef struct _php_basic_globals {
HashTable url_adapt_output_hosts_ht;
HashTable *user_filter_map;

/* file.c */
#if defined(_REENTRANT)
/* php_mblen() */
mbstate_t mblen_state;
#endif
bool mblen_ascii_singletons;

int umask;
zend_long unserialize_max_depth;
Expand Down
4 changes: 4 additions & 0 deletions ext/standard/exec.c
Original file line number Diff line number Diff line change
Expand Up @@ -287,11 +287,13 @@ PHPAPI zend_string *php_escape_shell_cmd(const zend_string *unescaped_cmd)

cmd = zend_string_safe_alloc(2, l, 0, 0);

php_mb_reset();
for (x = 0, y = 0; x < l; x++) {
int mb_len = php_mblen(str + x, (l - x));

/* skip non-valid multibyte characters */
if (mb_len < 0) {
php_mb_reset();
continue;
} else if (mb_len > 1) {
memcpy(ZSTR_VAL(cmd) + y, str + x, mb_len);
Expand Down Expand Up @@ -400,11 +402,13 @@ PHPAPI zend_string *php_escape_shell_arg(const zend_string *unescaped_arg)
ZSTR_VAL(cmd)[y++] = '\'';
#endif

php_mb_reset();
for (x = 0; x < l; x++) {
int mb_len = php_mblen(str + x, (l - x));

/* skip non-valid multibyte characters */
if (mb_len < 0) {
php_mb_reset();
continue;
} else if (mb_len > 1) {
memcpy(ZSTR_VAL(cmd) + y, str + x, mb_len);
Expand Down
35 changes: 25 additions & 10 deletions ext/standard/php_string.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,16 +57,31 @@ PHPAPI size_t php_strcspn(const char *s1, const char *s2, const char *s1_end, co

PHPAPI bool php_binary_string_shuffle(php_random_algo_with_state engine, char *str, zend_long len);

#ifdef _REENTRANT
# ifdef PHP_WIN32
# include <wchar.h>
# endif
# define php_mblen(ptr, len) ((int) mbrlen(ptr, len, &BG(mblen_state)))
# define php_mb_reset() memset(&BG(mblen_state), 0, sizeof(BG(mblen_state)))
#else
# define php_mblen(ptr, len) mblen(ptr, len)
# define php_mb_reset() php_ignore_value(mblen(NULL, 0))
#endif
#include <wchar.h>
/* Starts a new string. A byte below 0x80 is one character when the locale uses ASCII
* characters as singletons */
static zend_always_inline void php_mb_reset_ex(mbstate_t *state, bool *ascii_singletons)
{
memset(state, 0, sizeof(*state));
*ascii_singletons = CG(ascii_compatible_locale);
}

static zend_always_inline int php_mblen_ex(const char *ptr, size_t len, mbstate_t *state, bool ascii_singletons)
{
if (len > 0 && *ptr != '\0' && (unsigned char) *ptr < 0x80 && ascii_singletons) {
return 1;
}
int result = (int) mbrlen(ptr, len, state);
if (result == 0 && *ptr != '\0') {
/* A buffered character was flushed without consuming the byte; decode it from the initial state */
memset(state, 0, sizeof(*state));
result = (int) mbrlen(ptr, len, state);
}
return result;
}

#define php_mblen(ptr, len) php_mblen_ex(ptr, len, &BG(mblen_state), BG(mblen_ascii_singletons))
#define php_mb_reset() php_mb_reset_ex(&BG(mblen_state), &BG(mblen_ascii_singletons))

#define PHP_STR_PAD_LEFT 0
#define PHP_STR_PAD_RIGHT 1
Expand Down
1 change: 1 addition & 0 deletions ext/standard/string.c
Original file line number Diff line number Diff line change
Expand Up @@ -1482,6 +1482,7 @@ PHPAPI zend_string *php_basename(const char *s, size_t len, const char *suffix,
* State 1 is everything else. */
int state = 0;

php_mb_reset();
basename_start = s;
basename_end = s;
while (len > 0) {
Expand Down
Loading