aboutsummaryrefslogtreecommitdiffstats
path: root/lib/private/EmojiHelper.php
diff options
context:
space:
mode:
Diffstat (limited to 'lib/private/EmojiHelper.php')
-rw-r--r--lib/private/EmojiHelper.php79
1 files changed, 79 insertions, 0 deletions
diff --git a/lib/private/EmojiHelper.php b/lib/private/EmojiHelper.php
new file mode 100644
index 00000000000..52ab441e73a
--- /dev/null
+++ b/lib/private/EmojiHelper.php
@@ -0,0 +1,79 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OC;
+
+use OCP\IDBConnection;
+use OCP\IEmojiHelper;
+
+class EmojiHelper implements IEmojiHelper {
+ private IDBConnection $db;
+
+ public function __construct(IDBConnection $db) {
+ $this->db = $db;
+ }
+
+ public function doesPlatformSupportEmoji(): bool {
+ return $this->db->supports4ByteText()
+ && \class_exists(\IntlBreakIterator::class);
+ }
+
+ public function isValidSingleEmoji(string $emoji): bool {
+ $intlBreakIterator = \IntlBreakIterator::createCharacterInstance();
+ $intlBreakIterator->setText($emoji);
+
+ $characterCount = 0;
+ while ($intlBreakIterator->next() !== \IntlBreakIterator::DONE) {
+ $characterCount++;
+ }
+
+ if ($characterCount !== 1) {
+ return false;
+ }
+
+ $codePointIterator = \IntlBreakIterator::createCodePointInstance();
+ $codePointIterator->setText($emoji);
+
+ foreach ($codePointIterator->getPartsIterator() as $codePoint) {
+ $codePointType = \IntlChar::charType($codePoint);
+
+ // Unicode chars need 2 or more chars
+ // The characterCount before this loop already validate if is a single emoji
+ // This condition is to don't continue if non emoji chars
+ if (strlen($emoji) >= 2) {
+ // If the current code-point is an emoji or a modifier (like a skin-tone)
+ // just continue and check the next character
+ if ($codePointType === \IntlChar::CHAR_CATEGORY_MODIFIER_SYMBOL
+ || $codePointType === \IntlChar::CHAR_CATEGORY_MODIFIER_LETTER
+ || $codePointType === \IntlChar::CHAR_CATEGORY_OTHER_SYMBOL
+ || $codePointType === \IntlChar::CHAR_CATEGORY_FORMAT_CHAR // i.e. 🏴󠁧󠁢󠁥󠁮󠁧󠁿 🏴󠁧󠁢󠁳󠁣󠁴󠁿
+ || $codePointType === \IntlChar::CHAR_CATEGORY_OTHER_PUNCTUATION // i.e. ‼️ ⁉️ #⃣
+ || $codePointType === \IntlChar::CHAR_CATEGORY_LOWERCASE_LETTER // i.e. ℹ️
+ || $codePointType === \IntlChar::CHAR_CATEGORY_MATH_SYMBOL // i.e. ↔️ ◻️ ⤴️ ⤵️
+ || $codePointType === \IntlChar::CHAR_CATEGORY_ENCLOSING_MARK // i.e. 0⃣..9⃣
+ || $codePointType === \IntlChar::CHAR_CATEGORY_DECIMAL_DIGIT_NUMBER // i.e. 0⃣..9⃣
+ || $codePointType === \IntlChar::CHAR_CATEGORY_DASH_PUNCTUATION // i.e. 〰️
+ || $codePointType === \IntlChar::CHAR_CATEGORY_GENERAL_OTHER_TYPES
+ ) {
+ continue;
+ }
+ }
+
+ // If it's neither a modifier nor an emoji, we only allow
+ // a zero-width-joiner or a variation selector 16
+ $codePointValue = \IntlChar::ord($codePoint);
+ if ($codePointValue === 8205 || $codePointValue === 65039) {
+ continue;
+ }
+
+ return false;
+ }
+
+ return true;
+ }
+}