Upload files to 'user'
This commit is contained in:
203
user/EmojiDetector.php
Normal file
203
user/EmojiDetector.php
Normal file
@ -0,0 +1,203 @@
|
||||
<?php
|
||||
|
||||
namespace SteppingHat\EmojiDetector;
|
||||
|
||||
use Exception;
|
||||
use SteppingHat\EmojiDetector\Model\EmojiInfo;
|
||||
|
||||
class EmojiDetector {
|
||||
|
||||
const LONGEST_EMOJI = 8;
|
||||
|
||||
const SKIN_TONES = [
|
||||
'1F3FB' => 'skin-tone-2',
|
||||
'1F3FC' => 'skin-tone-3',
|
||||
'1F3FD' => 'skin-tone-4',
|
||||
'1F3FE' => 'skin-tone-5',
|
||||
'1F3FF' => 'skin-tone-6'
|
||||
];
|
||||
|
||||
private $map;
|
||||
private $regex;
|
||||
private $dataDir;
|
||||
|
||||
/**
|
||||
* EmojiDetector constructor.
|
||||
* @throws Exception
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->dataDir = __DIR__ . '/../var';
|
||||
$this->loadMap();
|
||||
$this->loadRawEmojis();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $string
|
||||
* @return EmojiInfo[]
|
||||
*/
|
||||
public function detect($string) {
|
||||
|
||||
$oldEncoding = mb_internal_encoding();
|
||||
mb_internal_encoding('UTF-8');
|
||||
|
||||
/** @var EmojiInfo[] $emojiInfos */
|
||||
$emojiInfos = [];
|
||||
|
||||
$matches = [];
|
||||
foreach($this->regex as $icon) {
|
||||
$strpos = mb_strpos($string, $icon);
|
||||
if($strpos !== false) {
|
||||
$matches[] = [$icon, $strpos];
|
||||
}
|
||||
}
|
||||
|
||||
$length = 0;
|
||||
|
||||
foreach($matches as $match) {
|
||||
$emojiInfo = new EmojiInfo();
|
||||
|
||||
$emojiInfo->setEmoji($match[0]);
|
||||
$emojiInfo->setOffset(strpos($string, $match[0]));
|
||||
$emojiInfo->setMbOffset(mb_strpos($string, $match[0]));
|
||||
|
||||
// Break apart the hex characters and build the hex string
|
||||
$hexCodes = [];
|
||||
|
||||
for($i = 0; $i < mb_strlen($emojiInfo->getEmoji()); $i++) {
|
||||
$hexCodes[] = strtoupper(dechex($this->unicodeOrd(mb_substr($match[0], $i, 1))));
|
||||
}
|
||||
$emojiInfo->setHexCodes($hexCodes);
|
||||
|
||||
// Denote the emoji name
|
||||
if(array_key_exists($emojiInfo->getHexString(), $this->map)) {
|
||||
$emojiInfo->setName($this->map[$emojiInfo->getHexString()]['name']);
|
||||
$emojiInfo->setShortName($this->map[$emojiInfo->getHexString()]['shortName']);
|
||||
$emojiInfo->setCategory($this->map[$emojiInfo->getHexString()]['category']);
|
||||
}
|
||||
|
||||
|
||||
// Denote the skin tone
|
||||
foreach($hexCodes as $hexCode) {
|
||||
if(array_key_exists($hexCode, self::SKIN_TONES)) {
|
||||
$emojiInfo->setSkinTone(self::SKIN_TONES[$hexCode]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$length += (strlen($emojiInfo->getEmoji()) - 1);
|
||||
|
||||
$emojiInfos[] = $emojiInfo;
|
||||
}
|
||||
|
||||
usort($emojiInfos, function(EmojiInfo $a, EmojiInfo $b) {
|
||||
if($a->getOffset() == $b->getOffset()) {
|
||||
return 0;
|
||||
}
|
||||
return $a->getOffset() < $b->getOffset() ? -1 : 1;
|
||||
});
|
||||
|
||||
/** @var EmojiInfo[] $data */
|
||||
$data = [];
|
||||
foreach($emojiInfos as $emoji) {
|
||||
if(count($data) == 0) {
|
||||
$data[] = $emoji;
|
||||
continue;
|
||||
}
|
||||
|
||||
/** @var EmojiInfo $last */
|
||||
$last = end($data);
|
||||
$key = key($data);
|
||||
|
||||
if($last->getOffset() == $emoji->getOffset()) {
|
||||
if($last->getMbLength() < $emoji->getMbLength()) {
|
||||
$data[$key] = $emoji;
|
||||
}
|
||||
} else if($emoji->getOffset() >= strlen($last->getEmoji()) + $last->getOffset()) {
|
||||
$data[] = $emoji;
|
||||
}
|
||||
|
||||
reset($data);
|
||||
}
|
||||
|
||||
mb_internal_encoding($oldEncoding);
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $string
|
||||
* @return bool
|
||||
*/
|
||||
public function isSingleEmoji($string) {
|
||||
if(mb_strlen($string) > self::LONGEST_EMOJI) return false;
|
||||
|
||||
$emojis = $this->detect($string);
|
||||
if(count($emojis) !== 1) return false;
|
||||
|
||||
$emoji = array_pop($emojis);
|
||||
$string = str_replace($emoji->getEmoji(), '', $string);
|
||||
|
||||
$split = $this->str_split_unicode($string);
|
||||
if(count($split) > 1) return false;
|
||||
else if(count($split) === 1 && $split[0] === '') return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function loadMap() {
|
||||
$mapFile = $this->dataDir . '/map.json';
|
||||
if(!file_exists($mapFile)) {
|
||||
throw new Exception("Could not load Emoji map file");
|
||||
}
|
||||
|
||||
$this->map = json_decode(file_get_contents($mapFile), true);
|
||||
|
||||
}
|
||||
|
||||
private function loadRawEmojis() {
|
||||
$mapFile = $this->dataDir . '/raw.json';
|
||||
if(!file_exists($mapFile)) {
|
||||
throw new Exception("Could not load Emoji raw file");
|
||||
}
|
||||
|
||||
$this->regex = json_decode(file_get_contents($mapFile), true);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $hexChar
|
||||
* @return bool|int
|
||||
*/
|
||||
private function unicodeOrd($hexChar) {
|
||||
$ord0 = ord($hexChar[0]);
|
||||
if($ord0 >= 0 && $ord0 <= 127) return $ord0;
|
||||
|
||||
$ord1 = ord($hexChar[1]);
|
||||
if($ord0 >= 192 && $ord0 <= 223) return ($ord0 - 192) * 64 + ($ord1 - 128);
|
||||
|
||||
$ord2 = ord($hexChar[2]);
|
||||
if($ord0 >= 224 && $ord0 <= 239) return ($ord0 - 224) * 4096 + ($ord1 - 128) * 64 + ($ord2 - 128);
|
||||
|
||||
$ord3 = ord($hexChar[3]);
|
||||
if($ord0 >= 240 && $ord0 <= 247) return ($ord0 - 240) * 262144 + ($ord1 - 128) * 4096 + ($ord2 - 128) * 64 + ($ord3 - 128);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $str
|
||||
* @param int $l
|
||||
* @return false|string[]
|
||||
*/
|
||||
private function str_split_unicode($str, $l = 0) {
|
||||
if ($l > 0) {
|
||||
$ret = array();
|
||||
$len = mb_strlen($str, "UTF-8");
|
||||
for ($i = 0; $i < $len; $i += $l) {
|
||||
$ret[] = mb_substr($str, $i, $l, "UTF-8");
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
return preg_split("//u", $str, -1, PREG_SPLIT_NO_EMPTY);
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user