ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
UtfNormal Class Reference
+ Collaboration diagram for UtfNormal:

Static Public Member Functions

static cleanUp ($string)
 The ultimate convenience function! Clean up invalid UTF-8 sequences, and convert to normal form C, canonical composition. More...
 
static toNFC ($string)
 Convert a UTF-8 string to normal form C, canonical composition. More...
 
static toNFD ($string)
 Convert a UTF-8 string to normal form D, canonical decomposition. More...
 
static toNFKC ($string)
 Convert a UTF-8 string to normal form KC, compatibility composition. More...
 
static toNFKD ($string)
 Convert a UTF-8 string to normal form KD, compatibility decomposition. More...
 
static loadData ()
 Load the basic composition data if necessary. More...
 
static quickIsNFC ($string)
 Returns true if the string is definitely in NFC. More...
 
static quickIsNFCVerify (&$string)
 Returns true if the string is definitely in NFC. More...
 
static NFC ($string)
 
static NFD ($string)
 
static NFKC ($string)
 
static NFKD ($string)
 
static fastDecompose ($string, $map)
 Perform decomposition of a UTF-8 string into either D or KD form (depending on which decomposition map is passed to us). More...
 
static fastCombiningSort ($string)
 Sorts combining characters into canonical order. More...
 
static fastCompose ($string)
 Produces canonically composed sequences, i.e. More...
 
static placebo ($string)
 This is just used for the benchmark, comparing how long it takes to interate through a string without really doing anything of substance. More...
 

Detailed Description

Definition at line 112 of file UtfNormal.php.

Member Function Documentation

◆ cleanUp()

static UtfNormal::cleanUp (   $string)
static

The ultimate convenience function! Clean up invalid UTF-8 sequences, and convert to normal form C, canonical composition.

Fast return for pure ASCII strings; some lesser optimizations for strings containing only known-good characters. Not as fast as toNFC().

Parameters
string$stringa UTF-8 string
Returns
string a clean, shiny, normalized UTF-8 string

Definition at line 125 of file UtfNormal.php.

References NFC(), NORMALIZE_ICU, quickIsNFCVerify(), UNORM_NFC, UTF8_FFFE, UTF8_FFFF, and UTF8_REPLACEMENT.

Referenced by CleanUpTest\doTestBytes(), CleanUpTest\doTestDoubleBytes(), CleanUpTest\doTestTripleBytes(), CleanUpTest\testAscii(), CleanUpTest\testBomRegression(), CleanUpTest\testChunkRegression(), CleanUpTest\testForbiddenRegression(), CleanUpTest\testHangulRegression(), CleanUpTest\testInterposeRegression(), CleanUpTest\testLatin(), CleanUpTest\testLatinNormal(), CleanUpTest\testNull(), CleanUpTest\testOverlongRegression(), CleanUpTest\testSurrogateRegression(), and CleanUpTest\XtestAllChars().

126  {
127  if (NORMALIZE_ICU) {
128  # We exclude a few chars that ICU would not.
129  $string = preg_replace(
130  '/[\x00-\x08\x0b\x0c\x0e-\x1f]/',
132  $string
133  );
134  $string = str_replace(UTF8_FFFE, UTF8_REPLACEMENT, $string);
135  $string = str_replace(UTF8_FFFF, UTF8_REPLACEMENT, $string);
136 
137  # UnicodeString constructor fails if the string ends with a
138  # head byte. Add a junk char at the end, we'll strip it off.
139  return rtrim(utf8_normalize($string . "\x01", UNORM_NFC), "\x01");
140  } elseif (UtfNormal::quickIsNFCVerify($string)) {
141  # Side effect -- $string has had UTF-8 errors cleaned up.
142  return $string;
143  } else {
144  return UtfNormal::NFC($string);
145  }
146  }
const UTF8_FFFE
Definition: UtfNormal.php:78
const UNORM_NFC
Definition: UtfNormal.php:91
const UTF8_FFFF
Definition: UtfNormal.php:79
static NFC($string)
Definition: UtfNormal.php:517
const UTF8_REPLACEMENT
Definition: UtfNormal.php:68
const NORMALIZE_ICU
Definition: UtfNormal.php:96
static quickIsNFCVerify(&$string)
Returns true if the string is definitely in NFC.
Definition: UtfNormal.php:291
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ fastCombiningSort()

static UtfNormal::fastCombiningSort (   $string)
static

Sorts combining characters into canonical order.

This is the final step in creating decomposed normal forms D and KD.

Parameters
string$stringa valid, decomposed UTF-8 string. Input is not validated.
Returns
string a UTF-8 string with combining characters sorted in canonical order

Definition at line 638 of file UtfNormal.php.

References $c, $i, $n, $out, $utfCombiningClass, and loadData().

Referenced by NFD(), and NFKD().

639  {
641  global $utfCombiningClass;
642  $len = strlen($string);
643  $out = '';
644  $combiners = array();
645  $lastClass = -1;
646  for ($i = 0; $i < $len; $i++) {
647  $c = $string[$i];
648  $n = ord($c);
649  if ($n >= 0x80) {
650  if ($n >= 0xf0) {
651  $c = substr($string, $i, 4);
652  $i += 3;
653  } elseif ($n >= 0xe0) {
654  $c = substr($string, $i, 3);
655  $i += 2;
656  } elseif ($n >= 0xc0) {
657  $c = substr($string, $i, 2);
658  $i++;
659  }
660  if (isset($utfCombiningClass[$c])) {
661  $lastClass = $utfCombiningClass[$c];
662  if (isset($combiners[$lastClass])) {
663  $combiners[$lastClass] .= $c;
664  } else {
665  $combiners[$lastClass] = $c;
666  }
667  continue;
668  }
669  }
670  if ($lastClass) {
671  ksort($combiners);
672  $out .= implode('', $combiners);
673  $combiners = array();
674  }
675  $out .= $c;
676  $lastClass = 0;
677  }
678  if ($lastClass) {
679  ksort($combiners);
680  $out .= implode('', $combiners);
681  }
682  return $out;
683  }
global $utfCombiningClass
Definition: UtfNormal.php:21
static loadData()
Load the basic composition data if necessary.
Definition: UtfNormal.php:232
$n
Definition: RandomTest.php:85
$i
Definition: disco.tpl.php:19
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ fastCompose()

static UtfNormal::fastCompose (   $string)
static

Produces canonically composed sequences, i.e.

normal form C or KC.

Parameters
string$stringa valid UTF-8 string in sorted normal form D or KD. Input is not validated.
Returns
string a UTF-8 string with canonical precomposed characters used where possible

Definition at line 693 of file UtfNormal.php.

References $c, $i, $n, $out, $tail, $utfCanonicalComp, $utfCombiningClass, loadData(), UNICODE_HANGUL_FIRST, UNICODE_HANGUL_TCOUNT, UNICODE_HANGUL_VCOUNT, UTF8_HANGUL_FIRST, UTF8_HANGUL_LAST, UTF8_HANGUL_LBASE, UTF8_HANGUL_LEND, UTF8_HANGUL_TBASE, UTF8_HANGUL_TEND, UTF8_HANGUL_VBASE, and UTF8_HANGUL_VEND.

Referenced by NFC(), and NFKC().

694  {
697  $len = strlen($string);
698  $out = '';
699  $lastClass = -1;
700  $lastHangul = 0;
701  $startChar = '';
702  $combining = '';
703  $x1 = ord(substr(UTF8_HANGUL_VBASE, 0, 1));
704  $x2 = ord(substr(UTF8_HANGUL_TEND, 0, 1));
705  for ($i = 0; $i < $len; $i++) {
706  $c = $string[$i];
707  $n = ord($c);
708  if ($n < 0x80) {
709  # No combining characters here...
710  $out .= $startChar;
711  $out .= $combining;
712  $startChar = $c;
713  $combining = '';
714  $lastClass = 0;
715  continue;
716  } elseif ($n >= 0xf0) {
717  $c = substr($string, $i, 4);
718  $i += 3;
719  } elseif ($n >= 0xe0) {
720  $c = substr($string, $i, 3);
721  $i += 2;
722  } elseif ($n >= 0xc0) {
723  $c = substr($string, $i, 2);
724  $i++;
725  }
726  $pair = $startChar . $c;
727  if ($n > 0x80) {
728  if (isset($utfCombiningClass[$c])) {
729  # A combining char; see what we can do with it
730  $class = $utfCombiningClass[$c];
731  if (!empty($startChar) &&
732  $lastClass < $class &&
733  $class > 0 &&
734  isset($utfCanonicalComp[$pair])) {
735  $startChar = $utfCanonicalComp[$pair];
736  $class = 0;
737  } else {
738  $combining .= $c;
739  }
740  $lastClass = $class;
741  $lastHangul = 0;
742  continue;
743  }
744  }
745  # New start char
746  if ($lastClass == 0) {
747  if (isset($utfCanonicalComp[$pair])) {
748  $startChar = $utfCanonicalComp[$pair];
749  $lastHangul = 0;
750  continue;
751  }
752  if ($n >= $x1 && $n <= $x2) {
753  # WARNING: Hangul code is painfully slow.
754  # I apologize for this ugly, ugly code; however
755  # performance is even more teh suck if we call
756  # out to nice clean functions. Lookup tables are
757  # marginally faster, but require a lot of space.
758  #
759  if ($c >= UTF8_HANGUL_VBASE &&
760  $c <= UTF8_HANGUL_VEND &&
761  $startChar >= UTF8_HANGUL_LBASE &&
762  $startChar <= UTF8_HANGUL_LEND) {
763  #
764  #$lIndex = utf8ToCodepoint( $startChar ) - UNICODE_HANGUL_LBASE;
765  #$vIndex = utf8ToCodepoint( $c ) - UNICODE_HANGUL_VBASE;
766  $lIndex = ord($startChar[2]) - 0x80;
767  $vIndex = ord($c[2]) - 0xa1;
768 
769  $hangulPoint = UNICODE_HANGUL_FIRST +
771  (UNICODE_HANGUL_VCOUNT * $lIndex + $vIndex);
772 
773  # Hardcode the limited-range UTF-8 conversion:
774  $startChar = chr($hangulPoint >> 12 & 0x0f | 0xe0) .
775  chr($hangulPoint >> 6 & 0x3f | 0x80) .
776  chr($hangulPoint & 0x3f | 0x80);
777  $lastHangul = 0;
778  continue;
779  } elseif ($c >= UTF8_HANGUL_TBASE &&
780  $c <= UTF8_HANGUL_TEND &&
781  $startChar >= UTF8_HANGUL_FIRST &&
782  $startChar <= UTF8_HANGUL_LAST &&
783  !$lastHangul) {
784  # $tIndex = utf8ToCodepoint( $c ) - UNICODE_HANGUL_TBASE;
785  $tIndex = ord($c[2]) - 0xa7;
786  if ($tIndex < 0) {
787  $tIndex = ord($c[2]) - 0x80 + (0x11c0 - 0x11a7);
788  }
789 
790  # Increment the code point by $tIndex, without
791  # the function overhead of decoding and recoding UTF-8
792  #
793  $tail = ord($startChar[2]) + $tIndex;
794  if ($tail > 0xbf) {
795  $tail -= 0x40;
796  $mid = ord($startChar[1]) + 1;
797  if ($mid > 0xbf) {
798  $startChar[0] = chr(ord($startChar[0]) + 1);
799  $mid -= 0x40;
800  }
801  $startChar[1] = chr($mid);
802  }
803  $startChar[2] = chr($tail);
804 
805  # If there's another jamo char after this, *don't* try to merge it.
806  $lastHangul = 1;
807  continue;
808  }
809  }
810  }
811  $out .= $startChar;
812  $out .= $combining;
813  $startChar = $c;
814  $combining = '';
815  $lastClass = 0;
816  $lastHangul = 0;
817  }
818  $out .= $startChar . $combining;
819  return $out;
820  }
const UTF8_HANGUL_LEND
Definition: UtfNormal.php:61
const UTF8_HANGUL_FIRST
Definition: UtfNormal.php:54
const UNICODE_HANGUL_FIRST
Definition: UtfNormal.php:32
global $utfCombiningClass
Definition: UtfNormal.php:21
const UNICODE_HANGUL_VCOUNT
Definition: UtfNormal.php:40
const UNICODE_HANGUL_TCOUNT
Definition: UtfNormal.php:41
$tail
Definition: tail.php:20
const UTF8_HANGUL_VBASE
Definition: UtfNormal.php:58
const UTF8_HANGUL_LAST
Definition: UtfNormal.php:55
const UTF8_HANGUL_LBASE
Definition: UtfNormal.php:57
const UTF8_HANGUL_TBASE
Definition: UtfNormal.php:59
static loadData()
Load the basic composition data if necessary.
Definition: UtfNormal.php:232
const UTF8_HANGUL_TEND
Definition: UtfNormal.php:63
$n
Definition: RandomTest.php:85
global $utfCanonicalComp
Definition: UtfNormal.php:21
$i
Definition: disco.tpl.php:19
const UTF8_HANGUL_VEND
Definition: UtfNormal.php:62
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ fastDecompose()

static UtfNormal::fastDecompose (   $string,
  $map 
)
static

Perform decomposition of a UTF-8 string into either D or KD form (depending on which decomposition map is passed to us).

Input is assumed to be valid UTF-8. Invalid code will break.

Parameters
string$stringValid UTF-8 string
array$maphash of expanded decomposition map
Returns
string a UTF-8 string decomposed, not yet normalized (needs sorting)

Definition at line 576 of file UtfNormal.php.

References $c, $i, $index, $l, $map, $n, $out, $t, loadData(), UNICODE_HANGUL_FIRST, UNICODE_HANGUL_NCOUNT, UNICODE_HANGUL_TCOUNT, UTF8_HANGUL_FIRST, and UTF8_HANGUL_LAST.

Referenced by NFD(), and NFKD().

577  {
579  $len = strlen($string);
580  $out = '';
581  for ($i = 0; $i < $len; $i++) {
582  $c = $string[$i];
583  $n = ord($c);
584  if ($n < 0x80) {
585  # ASCII chars never decompose
586  # THEY ARE IMMORTAL
587  $out .= $c;
588  continue;
589  } elseif ($n >= 0xf0) {
590  $c = substr($string, $i, 4);
591  $i += 3;
592  } elseif ($n >= 0xe0) {
593  $c = substr($string, $i, 3);
594  $i += 2;
595  } elseif ($n >= 0xc0) {
596  $c = substr($string, $i, 2);
597  $i++;
598  }
599  if (isset($map[$c])) {
600  $out .= $map[$c];
601  continue;
602  } else {
603  if ($c >= UTF8_HANGUL_FIRST && $c <= UTF8_HANGUL_LAST) {
604  # Decompose a hangul syllable into jamo;
605  # hardcoded for three-byte UTF-8 sequence.
606  # A lookup table would be slightly faster,
607  # but adds a lot of memory & disk needs.
608  #
609  $index = ((ord($c[0]) & 0x0f) << 12
610  | (ord($c[1]) & 0x3f) << 6
611  | (ord($c[2]) & 0x3f))
613  $l = intval($index / UNICODE_HANGUL_NCOUNT);
616  $out .= "\xe1\x84" . chr(0x80 + $l) . "\xe1\x85" . chr(0xa1 + $v);
617  if ($t >= 25) {
618  $out .= "\xe1\x87" . chr(0x80 + $t - 25);
619  } elseif ($t) {
620  $out .= "\xe1\x86" . chr(0xa7 + $t);
621  }
622  continue;
623  }
624  }
625  $out .= $c;
626  }
627  return $out;
628  }
const UTF8_HANGUL_FIRST
Definition: UtfNormal.php:54
const UNICODE_HANGUL_FIRST
Definition: UtfNormal.php:32
const UNICODE_HANGUL_TCOUNT
Definition: UtfNormal.php:41
const UTF8_HANGUL_LAST
Definition: UtfNormal.php:55
$index
Definition: metadata.php:60
static loadData()
Load the basic composition data if necessary.
Definition: UtfNormal.php:232
$n
Definition: RandomTest.php:85
global $l
Definition: afr.php:30
const UNICODE_HANGUL_NCOUNT
Definition: UtfNormal.php:42
$i
Definition: disco.tpl.php:19
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ loadData()

static UtfNormal::loadData ( )
static

Load the basic composition data if necessary.

Definition at line 232 of file UtfNormal.php.

References $utfCombiningClass.

Referenced by fastCombiningSort(), fastCompose(), fastDecompose(), NFD(), quickIsNFC(), and quickIsNFCVerify().

233  {
234  global $utfCombiningClass;
235  if (!isset($utfCombiningClass)) {
236  require_once(dirname(__FILE__) . '/UtfNormalData.inc');
237  }
238  }
global $utfCombiningClass
Definition: UtfNormal.php:21
+ Here is the caller graph for this function:

◆ NFC()

static UtfNormal::NFC (   $string)
static
Parameters
string$string
Returns
string

Definition at line 517 of file UtfNormal.php.

References fastCompose(), and NFD().

Referenced by cleanUp(), CleanUpTest\doTestDoubleBytes(), CleanUpTest\doTestTripleBytes(), toNFC(), and CleanUpTest\XtestAllChars().

518  {
519  return UtfNormal::fastCompose(UtfNormal::NFD($string));
520  }
static NFD($string)
Definition: UtfNormal.php:528
static fastCompose($string)
Produces canonically composed sequences, i.e.
Definition: UtfNormal.php:693
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ NFD()

static UtfNormal::NFD (   $string)
static
Parameters
string$string
Returns
string

Definition at line 528 of file UtfNormal.php.

References $utfCanonicalDecomp, fastCombiningSort(), fastDecompose(), and loadData().

Referenced by NFC(), and toNFD().

529  {
531  global $utfCanonicalDecomp;
533  UtfNormal::fastDecompose($string, $utfCanonicalDecomp)
534  );
535  }
global $utfCanonicalDecomp
Definition: UtfNormal.php:21
static loadData()
Load the basic composition data if necessary.
Definition: UtfNormal.php:232
static fastCombiningSort($string)
Sorts combining characters into canonical order.
Definition: UtfNormal.php:638
static fastDecompose($string, $map)
Perform decomposition of a UTF-8 string into either D or KD form (depending on which decomposition ma...
Definition: UtfNormal.php:576
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ NFKC()

static UtfNormal::NFKC (   $string)
static
Parameters
string$string
Returns
string

Definition at line 543 of file UtfNormal.php.

References fastCompose(), and NFKD().

Referenced by toNFKC().

544  {
545  return UtfNormal::fastCompose(UtfNormal::NFKD($string));
546  }
static fastCompose($string)
Produces canonically composed sequences, i.e.
Definition: UtfNormal.php:693
static NFKD($string)
Definition: UtfNormal.php:554
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ NFKD()

static UtfNormal::NFKD (   $string)
static
Parameters
string$string
Returns
string

Definition at line 554 of file UtfNormal.php.

References $utfCompatibilityDecomp, fastCombiningSort(), and fastDecompose().

Referenced by NFKC(), and toNFKD().

555  {
557  if (!isset($utfCompatibilityDecomp)) {
558  require_once('UtfNormalDataK.inc');
559  }
561  UtfNormal::fastDecompose($string, $utfCompatibilityDecomp)
562  );
563  }
static fastCombiningSort($string)
Sorts combining characters into canonical order.
Definition: UtfNormal.php:638
static fastDecompose($string, $map)
Perform decomposition of a UTF-8 string into either D or KD form (depending on which decomposition ma...
Definition: UtfNormal.php:576
global $utfCompatibilityDecomp
Definition: UtfNormal.php:29
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ placebo()

static UtfNormal::placebo (   $string)
static

This is just used for the benchmark, comparing how long it takes to interate through a string without really doing anything of substance.

Parameters
string$string
Returns
string

Definition at line 829 of file UtfNormal.php.

References $i, and $out.

830  {
831  $len = strlen($string);
832  $out = '';
833  for ($i = 0; $i < $len; $i++) {
834  $out .= $string[$i];
835  }
836  return $out;
837  }
$i
Definition: disco.tpl.php:19

◆ quickIsNFC()

static UtfNormal::quickIsNFC (   $string)
static

Returns true if the string is definitely in NFC.

Returns false if not or uncertain.

Parameters
string$stringa valid UTF-8 string. Input is not validated.
Returns
bool

Definition at line 247 of file UtfNormal.php.

References $c, $i, $n, $utfCombiningClass, and loadData().

Referenced by toNFC().

248  {
249  # ASCII is always valid NFC!
250  # If it's pure ASCII, let it through.
251  if (!preg_match('/[\x80-\xff]/', $string)) {
252  return true;
253  }
254 
256  global $utfCheckNFC, $utfCombiningClass;
257  $len = strlen($string);
258  for ($i = 0; $i < $len; $i++) {
259  $c = $string[$i];
260  $n = ord($c);
261  if ($n < 0x80) {
262  continue;
263  } elseif ($n >= 0xf0) {
264  $c = substr($string, $i, 4);
265  $i += 3;
266  } elseif ($n >= 0xe0) {
267  $c = substr($string, $i, 3);
268  $i += 2;
269  } elseif ($n >= 0xc0) {
270  $c = substr($string, $i, 2);
271  $i++;
272  }
273  if (isset($utfCheckNFC[$c])) {
274  # If it's NO or MAYBE, bail and do the slow check.
275  return false;
276  }
277  if (isset($utfCombiningClass[$c])) {
278  # Combining character? We might have to do sorting, at least.
279  return false;
280  }
281  }
282  return true;
283  }
global $utfCombiningClass
Definition: UtfNormal.php:21
static loadData()
Load the basic composition data if necessary.
Definition: UtfNormal.php:232
$n
Definition: RandomTest.php:85
$i
Definition: disco.tpl.php:19
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ quickIsNFCVerify()

static UtfNormal::quickIsNFCVerify ( $string)
static

Returns true if the string is definitely in NFC.

Returns false if not or uncertain.

Parameters
string$stringa UTF-8 string, altered on output to be valid UTF-8 safe for XML.

Definition at line 291 of file UtfNormal.php.

References $base, $c, $i, $n, $out, $remaining, $start, $utfCombiningClass, down(), Sabre\Event\Loop\instance(), loadData(), UTF8_FFFE, UTF8_FFFF, UTF8_MAX, UTF8_OVERLONG_A, UTF8_OVERLONG_B, UTF8_OVERLONG_C, UTF8_REPLACEMENT, and UTF8_SURROGATE_FIRST.

Referenced by cleanUp().

292  {
293  # Screen out some characters that eg won't be allowed in XML
294  $string = preg_replace('/[\x00-\x08\x0b\x0c\x0e-\x1f]/', UTF8_REPLACEMENT, $string);
295 
296  # ASCII is always valid NFC!
297  # If we're only ever given plain ASCII, we can avoid the overhead
298  # of initializing the decomposition tables by skipping out early.
299  if (!preg_match('/[\x80-\xff]/', $string)) {
300  return true;
301  }
302 
303  static $checkit = null, $tailBytes = null, $utfCheckOrCombining = null;
304  if (!isset($checkit)) {
305  # Load/build some scary lookup tables...
307  global $utfCheckNFC, $utfCombiningClass;
308 
309  $utfCheckOrCombining = array_merge($utfCheckNFC, $utfCombiningClass);
310 
311  # Head bytes for sequences which we should do further validity checks
312  $checkit = array_flip(array_map(
313  'chr',
314  array( 0xc0, 0xc1, 0xe0, 0xed, 0xef,
315  0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
316  0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff )
317  ));
318 
319  # Each UTF-8 head byte is followed by a certain
320  # number of tail bytes.
321  $tailBytes = array();
322  for ($n = 0; $n < 256; $n++) {
323  if ($n < 0xc0) {
324  $remaining = 0;
325  } elseif ($n < 0xe0) {
326  $remaining = 1;
327  } elseif ($n < 0xf0) {
328  $remaining = 2;
329  } elseif ($n < 0xf8) {
330  $remaining = 3;
331  } elseif ($n < 0xfc) {
332  $remaining = 4;
333  } elseif ($n < 0xfe) {
334  $remaining = 5;
335  } else {
336  $remaining = 0;
337  }
338  $tailBytes[chr($n)] = $remaining;
339  }
340  }
341 
342  # Chop the text into pure-ASCII and non-ASCII areas;
343  # large ASCII parts can be handled much more quickly.
344  # Don't chop up Unicode areas for punctuation, though,
345  # that wastes energy.
346  $matches = array();
347  preg_match_all(
348  '/([\x00-\x7f]+|[\x80-\xff][\x00-\x40\x5b-\x5f\x7b-\xff]*)/',
349  $string,
350  $matches
351  );
352 
353  $looksNormal = true;
354  $base = 0;
355  $replace = array();
356  foreach ($matches[1] as $str) {
357  $chunk = strlen($str);
358 
359  if ($str[0] < "\x80") {
360  # ASCII chunk: guaranteed to be valid UTF-8
361  # and in normal form C, so skip over it.
362  $base += $chunk;
363  continue;
364  }
365 
366  # We'll have to examine the chunk byte by byte to ensure
367  # that it consists of valid UTF-8 sequences, and to see
368  # if any of them might not be normalized.
369  #
370  # Since PHP is not the fastest language on earth, some of
371  # this code is a little ugly with inner loop optimizations.
372 
373  $head = '';
374  $len = $chunk + 1; # Counting down is faster. I'm *so* sorry.
375 
376  for ($i = -1; --$len;) {
377  if ($remaining = $tailBytes[$c = $str[++$i]]) {
378  # UTF-8 head byte!
379  $sequence = $head = $c;
380  do {
381  # Look for the defined number of tail bytes...
382  if (--$len && ($c = $str[++$i]) >= "\x80" && $c < "\xc0") {
383  # Legal tail bytes are nice.
384  $sequence .= $c;
385  } else {
386  if (0 == $len) {
387  # Premature end of string!
388  # Drop a replacement character into output to
389  # represent the invalid UTF-8 sequence.
390  $replace[] = array( UTF8_REPLACEMENT,
391  $base + $i + 1 - strlen($sequence),
392  strlen($sequence) );
393  break 2;
394  } else {
395  # Illegal tail byte; abandon the sequence.
396  $replace[] = array( UTF8_REPLACEMENT,
397  $base + $i - strlen($sequence),
398  strlen($sequence) );
399  # Back up and reprocess this byte; it may itself
400  # be a legal ASCII or UTF-8 sequence head.
401  --$i;
402  ++$len;
403  continue 2;
404  }
405  }
406  } while (--$remaining);
407 
408  if (isset($checkit[$head])) {
409  # Do some more detailed validity checks, for
410  # invalid characters and illegal sequences.
411  if ($head == "\xed") {
412  # 0xed is relatively frequent in Korean, which
413  # abuts the surrogate area, so we're doing
414  # this check separately to speed things up.
415 
416  if ($sequence >= UTF8_SURROGATE_FIRST) {
417  # Surrogates are legal only in UTF-16 code.
418  # They are totally forbidden here in UTF-8
419  # utopia.
420  $replace[] = array( UTF8_REPLACEMENT,
421  $base + $i + 1 - strlen($sequence),
422  strlen($sequence) );
423  $head = '';
424  continue;
425  }
426  } else {
427  # Slower, but rarer checks...
428  $n = ord($head);
429  if (
430  # "Overlong sequences" are those that are syntactically
431  # correct but use more UTF-8 bytes than are necessary to
432  # encode a character. Naïve string comparisons can be
433  # tricked into failing to see a match for an ASCII
434  # character, for instance, which can be a security hole
435  # if blacklist checks are being used.
436  ($n < 0xc2 && $sequence <= UTF8_OVERLONG_A)
437  || ($n == 0xe0 && $sequence <= UTF8_OVERLONG_B)
438  || ($n == 0xf0 && $sequence <= UTF8_OVERLONG_C)
439 
440  # U+FFFE and U+FFFF are explicitly forbidden in Unicode.
441  || ($n == 0xef &&
442  ($sequence == UTF8_FFFE)
443  || ($sequence == UTF8_FFFF))
444 
445  # Unicode has been limited to 21 bits; longer
446  # sequences are not allowed.
447  || ($n >= 0xf0 && $sequence > UTF8_MAX)) {
448  $replace[] = array( UTF8_REPLACEMENT,
449  $base + $i + 1 - strlen($sequence),
450  strlen($sequence) );
451  $head = '';
452  continue;
453  }
454  }
455  }
456 
457  if (isset($utfCheckOrCombining[$sequence])) {
458  # If it's NO or MAYBE, we'll have to rip
459  # the string apart and put it back together.
460  # That's going to be mighty slow.
461  $looksNormal = false;
462  }
463 
464  # The sequence is legal!
465  $head = '';
466  } elseif ($c < "\x80") {
467  # ASCII byte.
468  $head = '';
469  } elseif ($c < "\xc0") {
470  # Illegal tail bytes
471  if ($head == '') {
472  # Out of the blue!
473  $replace[] = array( UTF8_REPLACEMENT, $base + $i, 1 );
474  } else {
475  # Don't add if we're continuing a broken sequence;
476  # we already put a replacement character when we looked
477  # at the broken sequence.
478  $replace[] = array( '', $base + $i, 1 );
479  }
480  } else {
481  # Miscellaneous freaks.
482  $replace[] = array( UTF8_REPLACEMENT, $base + $i, 1 );
483  $head = '';
484  }
485  }
486  $base += $chunk;
487  }
488  if (count($replace)) {
489  # There were illegal UTF-8 sequences we need to fix up.
490  $out = '';
491  $last = 0;
492  foreach ($replace as $rep) {
493  list($replacement, $start, $length) = $rep;
494  if ($last < $start) {
495  $out .= substr($string, $last, $start - $last);
496  }
497  $out .= $replacement;
498  $last = $start + $length;
499  }
500  if ($last < strlen($string)) {
501  $out .= substr($string, $last);
502  }
503  $string = $out;
504  }
505  return $looksNormal;
506  }
const UTF8_FFFE
Definition: UtfNormal.php:78
const UTF8_OVERLONG_C
Definition: UtfNormal.php:73
global $utfCombiningClass
Definition: UtfNormal.php:21
const UTF8_OVERLONG_B
Definition: UtfNormal.php:72
const UTF8_FFFF
Definition: UtfNormal.php:79
const UTF8_SURROGATE_FIRST
Definition: UtfNormal.php:65
if($state['core:TerminatedAssocId'] !==null) $remaining
down()
Definition: down.php:2
$start
Definition: bench.php:8
$base
Definition: index.php:4
static loadData()
Load the basic composition data if necessary.
Definition: UtfNormal.php:232
const UTF8_REPLACEMENT
Definition: UtfNormal.php:68
$n
Definition: RandomTest.php:85
instance(Loop $newLoop=null)
Retrieves or sets the global Loop object.
Definition: functions.php:173
$i
Definition: disco.tpl.php:19
const UTF8_MAX
Definition: UtfNormal.php:67
const UTF8_OVERLONG_A
Definition: UtfNormal.php:71
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ toNFC()

static UtfNormal::toNFC (   $string)
static

Convert a UTF-8 string to normal form C, canonical composition.

Fast return for pure ASCII strings; some lesser optimizations for strings containing only known-good characters.

Parameters
string$stringa valid UTF-8 string. Input is not validated.
Returns
string a UTF-8 string in normal form C

Definition at line 157 of file UtfNormal.php.

References NFC(), NORMALIZE_ICU, quickIsNFC(), and UNORM_NFC.

Referenced by ilWebDAVUtil\davDeslashify(), ilTree\getNodePathForTitlePath(), and ilStr\normalizeUtf8String().

158  {
159  if (NORMALIZE_ICU) {
160  return utf8_normalize($string, UNORM_NFC);
161  } elseif (UtfNormal::quickIsNFC($string)) {
162  return $string;
163  } else {
164  return UtfNormal::NFC($string);
165  }
166  }
const UNORM_NFC
Definition: UtfNormal.php:91
static NFC($string)
Definition: UtfNormal.php:517
const NORMALIZE_ICU
Definition: UtfNormal.php:96
static quickIsNFC($string)
Returns true if the string is definitely in NFC.
Definition: UtfNormal.php:247
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ toNFD()

static UtfNormal::toNFD (   $string)
static

Convert a UTF-8 string to normal form D, canonical decomposition.

Fast return for pure ASCII strings.

Parameters
string$stringa valid UTF-8 string. Input is not validated.
Returns
string a UTF-8 string in normal form D

Definition at line 176 of file UtfNormal.php.

References NFD(), NORMALIZE_ICU, and UNORM_NFD.

177  {
178  if (NORMALIZE_ICU) {
179  return utf8_normalize($string, UNORM_NFD);
180  } elseif (preg_match('/[\x80-\xff]/', $string)) {
181  return UtfNormal::NFD($string);
182  } else {
183  return $string;
184  }
185  }
static NFD($string)
Definition: UtfNormal.php:528
const UNORM_NFD
Definition: UtfNormal.php:89
const NORMALIZE_ICU
Definition: UtfNormal.php:96
+ Here is the call graph for this function:

◆ toNFKC()

static UtfNormal::toNFKC (   $string)
static

Convert a UTF-8 string to normal form KC, compatibility composition.

This may cause irreversible information loss, use judiciously. Fast return for pure ASCII strings.

Parameters
string$stringa valid UTF-8 string. Input is not validated.
Returns
string a UTF-8 string in normal form KC

Definition at line 196 of file UtfNormal.php.

References NFKC(), NORMALIZE_ICU, and UNORM_NFKC.

197  {
198  if (NORMALIZE_ICU) {
199  return utf8_normalize($string, UNORM_NFKC);
200  } elseif (preg_match('/[\x80-\xff]/', $string)) {
201  return UtfNormal::NFKC($string);
202  } else {
203  return $string;
204  }
205  }
static NFKC($string)
Definition: UtfNormal.php:543
const UNORM_NFKC
Definition: UtfNormal.php:93
const NORMALIZE_ICU
Definition: UtfNormal.php:96
+ Here is the call graph for this function:

◆ toNFKD()

static UtfNormal::toNFKD (   $string)
static

Convert a UTF-8 string to normal form KD, compatibility decomposition.

This may cause irreversible information loss, use judiciously. Fast return for pure ASCII strings.

Parameters
string$stringa valid UTF-8 string. Input is not validated.
Returns
string a UTF-8 string in normal form KD

Definition at line 216 of file UtfNormal.php.

References NFKD(), NORMALIZE_ICU, and UNORM_NFKD.

217  {
218  if (NORMALIZE_ICU) {
219  return utf8_normalize($string, UNORM_NFKD);
220  } elseif (preg_match('/[\x80-\xff]/', $string)) {
221  return UtfNormal::NFKD($string);
222  } else {
223  return $string;
224  }
225  }
const NORMALIZE_ICU
Definition: UtfNormal.php:96
static NFKD($string)
Definition: UtfNormal.php:554
const UNORM_NFKD
Definition: UtfNormal.php:90
+ Here is the call graph for this function:

The documentation for this class was generated from the following file: