概述
PHP源代码NEWS文件显示:
-
串
- 已实现的请求#66024(mb_chr()和mb_ord())(Masakielastic,Yasuo)
- 已实现的请求#65081(mb_scrub())(Masakielastic,Yasuo)
使用polyfill-mbstring
如果您没有安装
mbstring或要在PHP 7.2或更早版本中采用
通过Composer
1 | composer require symfony/polyfill-mbstring |
但是,并非本文??中介绍的所有功能都已被复制。
生成开发版本
创建仅包含最新历史记录的浅表克隆。
1 2 3 4 5 | git clone --depth=1 [email protected]:php/php-src.git cd php-src ./buildconf ./configure --enable-mbstring make |
确保
mbstring模块已加载。
1 | sapi/cli/php -m | grep mbstring |
启用国际模块
如果要使用PHP 7.0中引入的
1 | ./configure --enable-mbstring --enable-intl |
取消整理和更新存储库
执行
1 | git pull --unshallow |
检查功能是否可用
运行以下命令以查看是否看到小写的" a"。
1 | sapi/cli/php -r 'echo mb_chr(0x61), PHP_EOL;' |
现在,让我们准备一个脚本文件并执行它。
1 | sapi/cli/php test.php |
test.php
1 2 3 4 | var_dump( 'a' === mb_chr(0x61), 0x61 === mb_ord('a') ); |
PHP 5.6和更高版本的php.ini指令
有关规范更改的详细信息,请参阅yohgaki开发的RFC。
PHP 5.6和更高版本的
1 2 3 | var_dump( 'UTF-8' === ini_get('default_charset') ); |
从PHP 5.6开始,
同时添加了
根据
RFC,
1 2 3 4 5 | ini_set('internal_encoding', 'Shift_JIS'); var_dump( 'UTF-8' === mb_internal_encoding() ); |
功能规格
mb_chr
1 | string mb_chr(int $codepoint[, string $encoding = mb_internal_encoding()]) |
函数的返回值是与代码点相对应的字符。
让我们先尝试UTF-8。
1 2 3 | var_dump( "あ" === mb_chr(0x3042) ); |
如果希望在未安装日语字体或表情符号的终端上打开脚本代码,则可以使用PHP 7.0中引入的Unicode转义序列。
1 2 3 | var_dump( "\u{3042}" === mb_chr(0x3042) ); |
在
Shift_JIS的情况下,组成字符的字节字符串按原样以十六进制表示。
1 2 3 4 5 6 7 | $char = mb_convert_encoding('あ', 'Shift_JIS', 'UTF-8'); var_dump( $char === mb_chr(0x82a0, 'Shift_JIS'), "82a0" === bin2hex(mb_chr(0x82a0, 'Shift_JIS')), "\x82\xa0" === mb_chr(0x82a0, 'Shift_JIS') ); |
传统编码的最大字节数为4个字节。如果有更多字节的情况,请告诉我。尝试使用汉字编码GB18030的表情符号。我没有安装中文字体的设备,所以我没有看到它的外观。
1 2 3 4 5 6 7 | // U+1F418: Elephant $char = mb_convert_encoding("\u{1F418}", 'GB18030', 'UTF-8'); var_dump( $char === mb_chr(0x9439cb38, 'GB18030'), "\x94\x39\xCB\x38" === mb_chr(0x9439cb38, 'GB18030') ); |
现在让我们尝试UTF-8无效代码点。返回值是与
1 2 3 4 | var_dump( '?' === mb_chr(-1), "\u{003f}" === mb_chr(-1) ); |
UTF-8将U FFFD定义为替代字符。
1 2 3 4 5 | mb_substitute_character(0xfffd); var_dump( "\u{fffd}" === mb_chr(-1) ); |
如果指定了特定于通信或转换目的的字符编码,例如
1 | var_dump(false === mb_chr(0x61, 'ISO-2022-JP')); |
mb_ord
1 | int mb_ord(string $char[, string $encoding = mb_internal_encoding()]) |
让我们先尝试UTF-8。
1 2 3 4 | var_dump( 0x3042 === mb_ord('あ'), 0x3042 === mb_ord("\u3042") ); |
如果指定了无效的字节字符串,则将返回
1 2 3 | var_dump( 0x3f === mb_ord("\x80") ); |
尝试使用其他字符U FFFD。
1 2 3 4 5 | mb_substitute_character(0xfffd); var_dump( 0xfffd === mb_ord("\x80") ); |
mb_scrub
1 | string mb_scrub(string $str[, string $encoding = mb_internal_encoding()]) |
1 2 3 | var_dump( "あ?" === mb_scrub("あ\x80") ); |
尝试另一个替代字符。
1 2 3 4 5 | mb_substitute_character(0xfffd); var_dump( "あ\u{fffd}" === mb_scrub("あ\x80") ); |
您也可以使用
1 2 3 4 | var_dump( "あ?" === mb_scrub("あ\x80"), "あ?" === mb_convert_encoding("あ\x80", mb_internal_encoding()) ); |
通过组合
标准功能
1 2 3 | var_dump( "あ&\u{fffd}" === htmlspecialchars_decode(htmlspecialchars("あ&\x80", ENT_SUBSTITUTE)) ); |
如果已安装
intl模块,则可以使用
1 2 3 4 | var_dump( "あ\u{fffd}" === UConverter::transcode("あ\x80", 'UTF-8', 'UTF-8'), "あ\u{fffd}" === (new UConverter('UTF-8', 'UTF-8'))->convert("あ\x80") ); |
开发者说明
UTF-8基础知识
UTF-8有效代码点的范围是U 0000到U D7FF和U E 000到U 10FFFF。从U D800到U DFFF的范围称为代理字符。由于UTF-16只能使用不超过U FFFF的代码点,因此我们使用代理对(两个代理字符)来表示介于U 10000到U 10 FFFF之间的字符。
如果您想自己编写UTF-8处理,请参考以下文章。
- 从UTF-8字符中找到代码点
- 从代码点生成UTF-8字符
- 考虑到无效的字节字符串,从UTF-8字符串中逐字符提取字符
mb_chr
如果将无效的代码点指定为参数,则该函数将作为发出致命错误并停止处理的选项。对于此选项,函数的用户需要知道有效的代码点以防止其停止。世界上有许多不同的字符编码,这需要CMS和框架开发人员的大量知识。
由此可以说,在实现标准功能时,有必要问"使用该功能的最低知识是什么?"。
对于
mb_ord
如果指定了无效的字节字符串,则可以选择返回
在CMS或框架中使用此功能时,需要记住将无效字节字符串转换为备用字符的过程。
从上面的内容中,我没有选择返回
Go是
函数行为的参考。当Go使用与
mb_scrub
据我所知,
如前所述,名称mb_scrub取自Ruby的
与无效字节字符串有关的安全性问题可以在Tokumaru教授(ockeghem)的幻灯片中找到,"过去三年中解决了多少字符代码漏洞?"(2014年)和"系统学习安全性"。制作一个Web应用程序"(2011,SB Creative)。
未来发行
- 添加官方PHP手册
-
建议将字符编码选项添加到标准函数
chr 和ord -
与
mb_scrub 等效的str_scrub 提案