@@ -165,7 +165,7 @@ function safe_strlen( $str, $encoding = false ) {
165165 $ test_safe_strlen = getenv ( 'PHP_CLI_TOOLS_TEST_SAFE_STRLEN ' );
166166
167167 // Assume UTF-8 if no encoding given - `grapheme_strlen()` will return null if given non-UTF-8 string.
168- if ( ( ! $ encoding || 'UTF-8 ' === $ encoding ) && function_exists ( ' grapheme_strlen ' ) && null !== ( $ length = grapheme_strlen ( $ str ) ) ) {
168+ if ( ( ! $ encoding || 'UTF-8 ' === $ encoding ) && can_use_icu ( ) && null !== ( $ length = grapheme_strlen ( $ str ) ) ) {
169169 if ( ! $ test_safe_strlen || ( $ test_safe_strlen & 1 ) ) {
170170 return $ length ;
171171 }
@@ -220,7 +220,7 @@ function safe_substr( $str, $start, $length = false, $is_width = false, $encodin
220220 $ test_safe_substr = getenv ( 'PHP_CLI_TOOLS_TEST_SAFE_SUBSTR ' );
221221
222222 // Assume UTF-8 if no encoding given - `grapheme_substr()` will return false (not null like `grapheme_strlen()`) if given non-UTF-8 string.
223- if ( ( ! $ encoding || 'UTF-8 ' === $ encoding ) && function_exists ( ' grapheme_substr ' ) && false !== ( $ try = grapheme_substr ( $ str , $ start , $ length ) ) ) {
223+ if ( ( ! $ encoding || 'UTF-8 ' === $ encoding ) && can_use_icu ( ) && false !== ( $ try = grapheme_substr ( $ str , $ start , $ length ) ) ) {
224224 if ( ! $ test_safe_substr || ( $ test_safe_substr & 1 ) ) {
225225 return $ is_width ? _safe_substr_eaw ( $ try , $ length ) : $ try ;
226226 }
@@ -328,7 +328,7 @@ function strwidth( $string, $encoding = false ) {
328328 $ test_strwidth = getenv ( 'PHP_CLI_TOOLS_TEST_STRWIDTH ' );
329329
330330 // Assume UTF-8 if no encoding given - `grapheme_strlen()` will return null if given non-UTF-8 string.
331- if ( ( ! $ encoding || 'UTF-8 ' === $ encoding ) && function_exists ( ' grapheme_strlen ' ) && null !== ( $ width = grapheme_strlen ( $ string ) ) ) {
331+ if ( ( ! $ encoding || 'UTF-8 ' === $ encoding ) && can_use_icu ( ) && null !== ( $ width = grapheme_strlen ( $ string ) ) ) {
332332 if ( ! $ test_strwidth || ( $ test_strwidth & 1 ) ) {
333333 return $ width + preg_match_all ( $ eaw_regex , $ string , $ dummy /*needed for PHP 5.3*/ );
334334 }
@@ -356,6 +356,22 @@ function strwidth( $string, $encoding = false ) {
356356 return safe_strlen ( $ string , $ encoding );
357357}
358358
359+ /**
360+ * Returns whether ICU is modern enough not to flake out.
361+ *
362+ * @return bool
363+ */
364+ function can_use_icu () {
365+ static $ can_use_icu = null ;
366+
367+ if ( null === $ can_use_icu ) {
368+ // Choosing ICU 54, Unicode 7.0.
369+ $ can_use_icu = defined ( 'INTL_ICU_VERSION ' ) && version_compare ( INTL_ICU_VERSION , '54.1 ' , '>= ' ) && function_exists ( 'grapheme_strlen ' ) && function_exists ( 'grapheme_substr ' );
370+ }
371+
372+ return $ can_use_icu ;
373+ }
374+
359375/**
360376 * Returns whether PCRE Unicode extended grapheme cluster '\X' is available for use.
361377 *
@@ -367,8 +383,8 @@ function can_use_pcre_x() {
367383 if ( null === $ can_use_pcre_x ) {
368384 // '\X' introduced (as Unicde extended grapheme cluster) in PCRE 8.32 - see https://vcs.pcre.org/pcre/code/tags/pcre-8.32/ChangeLog?view=markup line 53.
369385 // Older versions of PCRE were bundled with PHP <= 5.3.23 & <= 5.4.13.
370- $ unfc_pcre_version = substr ( PCRE_VERSION , 0 , strspn ( PCRE_VERSION , '0123456789. ' ) ); // Remove any trailing date stuff.
371- $ can_use_pcre_x = version_compare ( $ unfc_pcre_version , '8.32 ' , '>= ' ) && false !== @preg_match ( '/\X/u ' , '' );
386+ $ pcre_version = substr ( PCRE_VERSION , 0 , strspn ( PCRE_VERSION , '0123456789. ' ) ); // Remove any trailing date stuff.
387+ $ can_use_pcre_x = version_compare ( $ pcre_version , '8.32 ' , '>= ' ) && false !== @preg_match ( '/\X/u ' , '' );
372388 }
373389
374390 return $ can_use_pcre_x ;
0 commit comments