设计决策:使用PHP匹配JSON中的西里尔字符

时间:2015-04-18 20:50:57

标签: php regex json character-encoding http-headers

我正在为CMS开发一个插件,并且有一个意料之外的问题:因为插件是启用多个启用的,所以输入可以是任何unicode字符集。该插件以 json 格式保存数据,并包含属性为valuelookup的对象。对于value,一切都很好,但PHP使用lookup属性来检索这些实体,并在某些点通过正则表达式(内容过滤器)。 问题是:

  1. 对于非拉丁字符(例如Экспорт),正则表达式中的\w(word-char)不匹配。 有没有办法将西里尔字母识别为单词字符?还有其他隐藏的捕获物吗?
  2. 数据格式为JSON,非拉丁字符转换为JS unicodes,例如上面的\u042D\u043A\u0441\u043F\u043E\u0440\u0442安全这样做吗?(服务器限制等)
  3. 我所遇到的大“设计”问题源于前两个问题:

    我应该允许使用非拉丁字母语言的用户将自己的字符用于lookup属性,还是应该强制它们使用传统的“字”字符,即a,b,c等+下划线(因此是另一种语言的字母表)?我欢迎技术建议来指导这个决定(而不是UX)。

1 个答案:

答案 0 :(得分:1)

第一个问题

  

对于非拉丁字符(例如Экспорт),正则表达式中的\w(word-char)不匹配。有没有办法将西里尔字母识别为单词字符?还有其他隐藏的捕获物吗?

您只需打开u标志:

preg_match("#^\w+$#u", $str);

Demo

PHP docs在这里有误导性:

  你好(PCRE_UTF8
  此修饰符打开与Perl不兼容的PCRE的其他功能。模式和主题字符串被视为UTF-8。此修饰符可从Unix上的PHP 4.1.0或更高版本以及win32上的PHP 4.2.3获得。自PHP 4.3.5起,检查模式和主题的UTF-8有效性。无效主题将导致preg_ *函数无匹配;无效模式将触发级别E_WARNING的错误。自PHP 5.3.4起,五个和六个八位字节UTF-8序列被视为无效(分别为PCRE 7.3 2007-08-28);以前那些被认为是有效的UTF-8。

我说它有误导性,因为从上面的ideone测试中,它不仅启用了PCRE_UTF8,还启用了PCRE_UCP( Unicode字符属性),这就是你想要的行为。

以下是PCRE文档所说的内容:

  

PCRE_UTF8
  此选项使PCRE将模式和主题视为UTF-8字符串而不是单字节字符串。但是,只有在构建PCRE以包含UTF支持时才可用。如果没有,使用此选项会引发错误。有关此选项如何更改PCRE行为的详细信息,请参阅pcreunicode页面。

     

PCRE_UCP
  此选项更改了PCRE处理\B\b\D\d\S\s\W,{的方式{1}}和一些POSIX字符类。默认情况下,只识别ASCII字符,但如果设置了\w,则使用Unicode属性来对字符进行分类。有关详细信息,请参阅pcrepattern页面中有关通用字符类型的部分。如果设置PCRE_UCP,则匹配其影响的项目之一需要更长时间。只有在使用Unicode属性支持编译PCRE时,该选项才可用。

如果你想乍一看明显的,那么PCRE_UCP标志就会被设置,你可以在开始的时候将它插入模式中,就像那样:

PCRE_UCP
  

可能出现在模式开头的另一个特殊序列是preg_match("#(*UCP)^\w+$#u", $str); 。这与设置(*UCP)选项具有相同的效果:它会导致PCRE_UCP\d等序列使用Unicode属性来确定字符类型,而不是仅识别代码小于128的字符通过查询表。

第二个问题

  

数据格式为JSON,非拉丁字符转换为JS unicodes,例如上面的\w。不这样做是否安全? (服务器限制等)

只要您的\u042D\u043A\u0441\u043F\u043E\u0440\u0442标头定义了正确的编码,就不会这样做。

所以你可能想要使用类似的东西:

Content-Type

并确保您实际以UTF8发送。

但是,在转义序列中对这些字符进行编码会使整个ASCII兼容,因此您基本上可以通过这种方式完全解决问题。

设计问题

  

我应该允许使用非拉丁字母语言的用户将自己的字符用于header('Content-Type: application/json; charset=utf-8'); 属性,还是应该强制它们使用传统的“字”字符,即a,b,c等+下划线(因此是另一种语言的字母表)?我欢迎技术建议来指导这个决定(而不是UX)。

从技术上讲,只要您的整个堆栈支持Unicode(浏览器,PHP,数据库等),我认为这种方法没有问题。只需确保测试它并在数据库中使用启用Unicode的列类型。

要小心,PHP是一种可靠的字符串支持语言,因此您必须确保使用正确的函数(避免使用非{1}}之类的非Unicode感知函数,除非您真的需要字节数。) / p>

确保一切正常运行可能需要更多的工作,但是如果你想支持它,那就没问题了。