PHP如何处理emoji表情存入utf8的数据库?

一般Mysql表设计时,都是用UTF8字符集的。把带有emoji的昵称字段往里面insert一下就没了,整个字段变成了空字符串。这是怎么回事呢?

原来是因为Mysql的utf8字符集是3字节的,而emoji是4字节,这样整个昵称就无法存储了。这要怎么办呢
1、使用utf8mb4字符集
1、mysql的版本必须为v5.5.3或更高 2、把数据库的编码改成utf8mb4 -- UTF-8 Unicode 3、然后需要存储emoji表情的字段选择utf8mb4_general_ci 4、数据库连接也需要改为utf8mb4 这种方式可能带来的问题: 存储:在数据表中,对于变长的字段(如VARCHAR2,TEXT),utf8mb4最大可存储的字符可能少于utf8系列的collation;
在索引中,对于文本类型的字段,utf8mb4可索引的字符少于utf8系列的collations。如InnoDB的索引最多使用767字节。
如果使用utf8mb4,每一个字符都会预留4字节做索引,而utf8则预留3字节。故此前者是191个字符,后者是255个字符。 性能:由于以上原因,加上字符集大,utf8mb4的性能可能比utf8系列的collations低,
可以参考stackoverfolow上的一个测试结果:http://stackoverflow.com/questions/766809/whats-the-difference-between-utf8-general-ci-and-utf8-unicode-ci,
差异不是特别大。 运维:如果一个大的环境内,如果其他的数据库都是utf8模式,把其中某个库设置为utf8mb4模式,在后续交接运维可能会造成问题,遗留下坑。 上下游:数据库支持unicode的emoji存储,上下游不一定支持。比如mysql客户端驱动(低版本的jdbc就不行)可能不支持utf8mb4,或者DDL的中间件不支持utf8mb4。
web端处理utf8mb4字符展示,这些都有可能影响emoji的存储活着展示。
2、使用base64编码
这种方法是可以,但是旧数据如果没有经过encode操作,取数据的时候如果统一进行decode的话,旧数据会丢失的。
3、过滤emoji表情
支持emoji表情是个麻烦的东西,有时即使能存储,也不一定能完美显示。可能会出现因emoji图片不够全而出现无法显示的情况。并且有些客户端可能还需要使用第三方类库,需要大量的emoji图片等。
因此,如果emoji不是非要不可,我们可以把带有emoji内容的数据过滤掉,达到不影响其他数据的存储。
// 过滤掉emoji表情
function filterEmoji($str)
{
   $str = preg_replace_callback('/./u',function (array $match) {
         return strlen($match[0]) >= 4 ? '' : $match[0];
      },$str);
   return $str;
}
4、文本转义emoji表情
/**
把用户输入的文本转义(主要针对特殊符号和emoji表情)
*/
public function userTextEncode($str){
  if (!is_string($str)) return $str;
  if (!$str || $str=='undefined') return '';
  
  $text = json_encode($str); //暴露出unicode
  $text = preg_replace_callback("/(\\\u[ed][0-9a-f]{3})/i",function($str){
    return addslashes($str[0]);
  },$text); //将emoji的unicode留下,其他不动,这里的正则比原答案增加了d,因为我发现我很多emoji实际上是\ud开头的,反而暂时没发现有\ue开头。
  return json_decode($text);
}
  
/**
解码上面的转义
*/
public function userTextDecode($str){
  $text = json_encode($str); //暴露出unicode
  $text = preg_replace_callback('/\\\\\\\\/i',function($str){
    return '\\';
  },$text); //将两条斜杠变成一条,其他不动
  return json_decode($text);
}