Home >Backend Development >PHP Tutorial >基于PHP扩展一种处置Emoji方法的类库介绍【Carmela】
基于PHP扩展一种处理Emoji方法的类库介绍【Carmela】
Carmela提供基于PHP,PHP扩展,JAVA,C++等语言的一套处理4四节UTF-8解决方案,比如常见Emoji标签支持
UTF-8格式含有Emoji表情字符串直接插入数据库,如果数据库未做调整会提示报错,通过更改数据库和表的字符集为utf8mb4_general_ci,可以避免这种问题。但是,在很多大型系统和架构中,修改数据库的字符集可能会引发很多的问题,比如PC端展示,新老数据兼容问题。针对这类问题,还有另外一种解决方案,入库前替换,出库后根据客户端类型做反向替换。
Carmela提供基于PHP扩展一套处理4四节UTF-8解决方案,可以把UTF-8中大于3个字节的UTF-8字符替换成ubb模式,比如某UTF-8字符%f0%9f%91%a4(为了展示方便,展示emoji标签的encode模式),替换后的样子[u]1f464[/u],同时从数据库读出时,根据不同的请求客户端(iOS,Andriod,PC)做反向替换。 Carmela的名字来源《不一样的卡梅拉》,《不一样的卡梅拉》系列故事讲的是母鸡卡梅拉和她的儿女们卡梅利多和卡门的历险故事,卡梅拉家族里的每个人都是那样的与众不同,敢于幻想,更敢于去尝试别人不敢想的事情。
1.编译打包
<code style="box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.6000003814697px; padding: 0px; margin: 0px; border-radius: 3px; word-break: normal; border: 0px; display: inline; max-width: initial; overflow: initial; line-height: inherit; word-wrap: normal; background: transparent;">git clone https://github.com/ugg/Carmela<php-bin>/phpize./configure --with-php-config=<php-path>/php-config-pathmakemake install</php-path></php-bin></code>
修改配置文件
vim /php.ini
添加以下内容
<code style="box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.6000003814697px; padding: 0px; margin: 0px; border-radius: 3px; word-break: normal; border: 0px; display: inline; max-width: initial; overflow: initial; line-height: inherit; word-wrap: normal; background: transparent;">[carmela] extension=carmela.so</code>
<code style="box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.6000003814697px; padding: 0px; margin: 0px; border-radius: 3px; word-break: normal; border: 0px; display: inline; max-width: initial; overflow: initial; line-height: inherit; word-wrap: normal; background: transparent;">$str = urldecode("This is test %F0%9F%98%9C+%F0%9F%98%99 by ugg");echo "str:".$str."\n";echo "ubb:".carmela_str2ubb($str)."\n";</code>
<code style="box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.6000003814697px; padding: 0px; margin: 0px; border-radius: 3px; word-break: normal; border: 0px; display: inline; max-width: initial; overflow: initial; line-height: inherit; word-wrap: normal; background: transparent;">str:This is test xxxx(CSDN Emoji不能展示用XXXX代替) by uggubb:This is test [u]1f61c[/u] [u]1f619[/u] by ugg</code>
<code style="box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.6000003814697px; padding: 0px; margin: 0px; border-radius: 3px; word-break: normal; border: 0px; display: inline; max-width: initial; overflow: initial; line-height: inherit; word-wrap: normal; background: transparent;">$str = urldecode("This is test %F0%9F%98%9C+%F0%9F%98%99 by ugg");$str = carmela_str2ubb($str);echo "ubb:".$str."\n";echo "str:".carmela_ubb2str($str)."\n";</code>
<code style="box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.6000003814697px; padding: 0px; margin: 0px; border-radius: 3px; word-break: normal; border: 0px; display: inline; max-width: initial; overflow: initial; line-height: inherit; word-wrap: normal; background: transparent;">ubb:This is test [u]1f61c[/u] [u]1f619[/u] by uggstr:This is test</code><code style="font-size: 13.6000003814697px; line-height: inherit; box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; padding: 0px; margin: 0px; border-radius: 3px; word-break: normal; border: 0px; display: inline; max-width: initial; overflow: initial; word-wrap: normal; background: transparent;">(CSDN Emoji不能展示用XXXX代替)</code><span style="font-size: 13.6000003814697px; line-height: inherit; background-color: transparent;"> by ugg</span>
截取包含emoji字符的字符串指定长度字符。
截取包含ubb标签的字符串的指定长度字符。
删除字符串中的emoji字符,非严格模式,3字节的emoji字符无法删除,主要用在一些。
删除包含ubb标签字符串中的ubb标签。
使用PHP分别实现了两种方法,分别使用PHP的str_replace方法和PHP查找四字节emoji,进行替换的方法,以及PHP扩展方式,使用相同数据分别进行测试,测试效果如下。
<code style="box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.6000003814697px; padding: 0px; margin: 0px; border-radius: 3px; word-break: normal; border: 0px; display: inline; max-width: initial; overflow: initial; line-height: inherit; word-wrap: normal; background: transparent;">=========================== 方案1:PHP str_replace方式 ==================================== EMOJI TO STRING ==========TIME:781.94ms,处理行数: 100,处理字数:10100,处理字节数:31028平均每行处理时间:7.819ms=========== STRING TO EMOJI ==========TIME:118.566ms,处理行数: 100,处理字数:18710,处理字节数:37793平均每行处理时间:1.186ms=========================== 方案2:PHP字符查找方式 ==================================== EMOJI TO STRING ==========TIME:51.526ms,处理行数: 100,处理字数:10100,处理字节数:31028平均每行处理时间:0.515ms=========== STRING TO EMOJI ==========TIME:27.959ms,处理行数: 100,处理字数:23092,处理字节数:41236平均每行处理时间:0.28ms=========================== 方案3:PHP扩展方式 ==================================== EMOJI TO STRING ==========TIME:0.721ms,处理行数: 100,处理字数:10100,处理字节数:31028平均每行处理时间:0.007ms=========== STRING TO EMOJI ==========TIME:0.956ms,处理行数: 100,处理字数:20308,处理字节数:38452平均每行处理时间:0.01ms</code>
从以上测试效果上来看,str_replace方式,性能非常的差。使用PHP直接编写替换函数方式,性能提升10倍多,而采用扩展方式后,性能提升明显,在把emoji从字符形式转换为ubb方式时,性能提升1000倍。
以上测试数据通过create_file.php可以动态生成。本测试用例,生成100行数据,每行100个字符,100字符中可以包含3-10个emoji字符,进行测试的,直接运行benchmark.php 查看运行性能。
处理四字节的emoji原理非常简单,通过字符对比找到emoji字符进行替换。难点就是在基本原理上如何提升性能,如何快速查找,替换。PHP扩展方式,为大家提供了一种思路,可以参考这种思路实现java,C#,js等等版本的。
在项目目录中的emoji目录下找到images目录,从web根目录创建emoji文件夹,把images文件夹整个拷贝到emoji文件下,调用encode.class.php里面的carmela_ubb2str方法,
<code style="box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.6000003814697px; padding: 0px; margin: 0px; border-radius: 3px; word-break: normal; border: 0px; display: inline; max-width: initial; overflow: initial; line-height: inherit; word-wrap: normal; background: transparent;">Util_Encode::carmela_ubb2str($str, "PC");</code>
即可在PC上展示Emoji表情,目前收集到的845个emoji表情,一些新的表情符号并没有纳入其中,当然,目前这种方法并没有写入PHP扩展中,性能相对来说并不高。
<code style="box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.6000003814697px; padding: 0px; margin: 0px; border-radius: 3px; word-break: normal; border: 0px; display: inline; max-width: initial; overflow: initial; line-height: inherit; word-wrap: normal; background: transparent;"></code>