前几天朋友的小程序遇到点问题,同样的代码,有些人就是注册不上,有些人就没问题。让我帮忙看。
看代码应该没问题,我自己试也没问题,很诡异。后来我发现,说注册不上的一个截图里,昵称里有一个雨滴的符号。我们知道,传统的编码是没有表情符号的,表情符号是 Unicode 后期才加进去的,那么会不会是数据库字段的问题?看了一眼,Laravel 默认创建的数据库,字符类型是 utf8mb4_unicode_ci,而他们数据库是 utf8_general_ci,Google 一下,找到下面这篇文章:
為什麼MYSQL要設定用UTF8MB4編碼 UTF8MB4_UNICODE_CI
里面提到:
當資料庫需要儲存或處理以下資料:emoji (手機端常用的表情字符)
应该使用 utf8mb4_unicode_ci,因为它会用更多的空间存储字符。基本锁定是字符集的问题。然后看到梦康大的一篇博文:直接使用 mysql utf8 存储 超过三个字节的 emoji 表情 ( 不使用 utf8mb4 ),决定参考他的方案,毕竟改库改表不是小事情。
不过时过境迁,梦康文中的 func_overload
已经可以用 mb_strlen($str, '8bit')
来替代,所以最后的代码大约是这样的:
// 替换
protected function encodeEmoji($input) {
$length = mb_strlen($input, 'utf-8');
$result = '';
for ($i = 0; $i < $length; $i++) {
$tmp = mb_substr($input, $i, 1, 'utf-8');
if (mb_strlen($tmp, '8bit') >= 4) {
$result .= '[[Emoji:' . rawurlencode($tmp) . ']]';
} else {
$result .= $tmp;
}
}
return $result;
}
// 替换回
protected function decodeEmoji($nickname) {
return preg_replace_callback('~\[\[Emoji:(.*?)\]\]~', function ($matches) {
return rawurldecode($matches[1]);
}, $nickname);
}
所以说,程序员心态要保持年轻,步调要跟年轻人保持一致,这样才更容易发现新问题,所以我的昵称已经改成“肉山🎩”了。
欢迎吐槽,共同进步