1<?php 2 3/* 4 * This file is part of the league/commonmark package. 5 * 6 * (c) Colin O'Dell <colinodell@gmail.com> 7 * 8 * Original code based on the CommonMark JS reference parser (https://bitly.com/commonmark-js) 9 * - (c) John MacFarlane 10 * 11 * For the full copyright and license information, please view the LICENSE 12 * file that was distributed with this source code. 13 */ 14 15namespace League\CommonMark\Util; 16 17final class Html5EntityDecoder 18{ 19 public static function decode(string $entity): string 20 { 21 if (\substr($entity, -1) !== ';') { 22 return $entity; 23 } 24 25 if (\substr($entity, 0, 2) === '&#') { 26 if (\strtolower(\substr($entity, 2, 1)) === 'x') { 27 return self::fromHex(\substr($entity, 3, -1)); 28 } 29 30 return self::fromDecimal(\substr($entity, 2, -1)); 31 } 32 33 return \html_entity_decode($entity, \ENT_QUOTES | \ENT_HTML5, 'UTF-8'); 34 } 35 36 /** 37 * @param mixed $number 38 * 39 * @return string 40 */ 41 private static function fromDecimal($number): string 42 { 43 // Only convert code points within planes 0-2, excluding NULL 44 if (empty($number) || $number > 0x2FFFF) { 45 return self::fromHex('fffd'); 46 } 47 48 $entity = '&#' . $number . ';'; 49 50 $converted = \mb_decode_numericentity($entity, [0x0, 0x2FFFF, 0, 0xFFFF], 'UTF-8'); 51 52 if ($converted === $entity) { 53 return self::fromHex('fffd'); 54 } 55 56 return $converted; 57 } 58 59 private static function fromHex(string $hexChars): string 60 { 61 return self::fromDecimal(\hexdec($hexChars)); 62 } 63} 64