如果没有Perl的Encode模块,如何将CGI输入转换为UTF-8?

时间:2010-09-19 12:41:21

标签: perl unicode utf-8

通过这个论坛,我了解到使用以下内容转换CGI输入(从escape()d Ajax调用或普通HTML表单发布)到 是个好主意UTF-8:

read (STDIN, $_, $ENV{CONTENT_LENGTH});
s{%([a-fA-F0-9]{2})}{ pack ('C', hex ($1)) }eg;
utf8::decode $_;

更安全的方式(例如,不允许伪造字符通过)是执行以下操作:

use Encode qw (decode);
read (STDIN, $_, $ENV{CONTENT_LENGTH});
s{%([a-fA-F0-9]{2})}{ pack ('C', hex ($1)) }eg;
decode ('UTF-8', $_, Encode::FB_CROAK);
但是,我非常希望避免使用任何模块(包括XSLoader,Exporter以及它们带来的任何其他模块)。该函数适用于大量mod_perl驱动的网站,我认为没有模块,性能和可维护性都会更好(特别是因为当前代码不使用任何模块)。

我想一种方法是检查Encode模块并去除用于“decode('UTF-8',$ _,Encode :: FB_CROAK)”调用的函数和常量。我不熟悉Unicode和Perl模块来做到这一点。也许其他人有能力这样做或者知道一种类似的,安全的“原生”方式进行UTF-8转换?

更新:

我更喜欢保持非模块化的东西,因为那时唯一的黑盒子就是Perl自己的编译器(当然除非你深入了解模块库)。

有时您会看到大型模块被一些特定的代码行替换。例如,代替CGI.pm模块(人们也喜欢它),可以使用以下内容来解析AJAX帖子:

my %Input;
if ($ENV{CONTENT_LENGTH}) {
    read (STDIN, $_, $ENV{CONTENT_LENGTH});
    foreach (split (/&/)) {
        tr/+/ /; s/%([a-fA-F0-9]{2})/pack("C", hex($1))/eg;
        if (m{^(\w+)=\s*(.*?)\s*$}s) { $Input{$1} = $2; }
        else { die ("bad input ($_)"); }
    }
}

以类似的方式,如果能够提取或复制Encode的UTF-8解码功能,那就太棒了。

2 个答案:

答案 0 :(得分:6)

不要预先优化。首先采用传统方式,然后进行配置文件和基准测试,以了解您需要优化的位置。人们通常会将所有时间都浪费在其他地方,所以开始蒙眼和被铐都不会给你任何好处。

不要害怕模块。 mod_perl的目的是尽可能少地加载所有内容,因此启动时间和模块加载时间无关紧要。

答案 1 :(得分:1)

请勿使用escape()来创建发布的数据。这与URL编码不兼容,它是一种突变的JavaScript奇怪,通常不应该使用。其中一个缺点是,它会根据UTF-16代码单元将非ASCII字符编码为非标准%uNNNN序列,而不是标准的URL编码的UTF-8。您当前的代码将无法处理。

您通常应该使用encodeURIComponent()

如果您必须自己对发布的输入进行URL解码而不是使用表单库(这确实意味着您将无法处理multipart/form-data),则需要将+符号转换为替换%之前的空格 - 序列。此替换是表单提交中的标准(虽然URL编码数据中没有其他地方)。

如果您确实不想使用库,请确保输入有效UTF-8,请尝试this regex。它还排除了一些控制字符(您可能需要调整它以排除更多)。