【问题标题】:Perl cgi and XML::Code double encoding issuePerl cgi 和 XML::Code 双重编码问题
【发布时间】:2012-09-27 22:24:41
【问题描述】:

我正在使用 XML::Code 从通过 CGI 模块接收的 GET 参数创建一些 XML 数据。网络服务器是 Apache,字符集设置为 UTF-8,提交表单位于带有

的页面上
<!DOCTYPE html>
<html lang="en-GB">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">

标题。 CGI 如下所示:

use CGI;
use Encode;
use XML::Code;
binmode(STDOUT, ":utf8");
binmode(STDIN, ":utf8");

my $cgi = CGI->new();
print $cgi->header(-type => "text/xml", -charset => "utf-8");
my $object = $cgi->param("object");
$object = decode("utf-8", utf8::upgrade($object));

my $content = XML::Code->new("formdata");
$content->version ("1.0");
$content->encoding ("UTF-8");

my $sub_content = XML::Code->new("object");
$sub_content->set_text($object);
$content->add_child($sub_content);

$sub_content = XML::Code->new("isutf");
$sub_content->set_text(utf8::is_utf8($object));
$content->add_child($sub_content);

print $content->code();

当使用http://mydomain.com/cgi-bin/formdata.pl?object=ö 调用 cgi 时,输出(从 firebug 复制)是

<?xml version="1.0" encoding="UTF-8"?>
<formdata>
    <object>ö</object>
    <isutf>1</isutf>
</formdata>

从 CGI 中删除 binmode(STDOUT, ":utf8") 给了我想要的东西

<?xml version="1.0" encoding="UTF-8"?>
<formdata>
    <object>ö</object>
    <isutf>1</isutf>
</formdata>

现在我知道如何解决这个问题,但我认为将所有内容都设置为 UTF-8 会很安全。如果我不是,那将意味着更多的测试。这是 perl 库中的错误还是我的想法?

最好, 马库斯

【问题讨论】:

    标签: xml perl utf-8 cgi


    【解决方案1】:

    我认为以下行:

    $object = decode("utf-8", utf8::upgrade($object));
    

    可能没有帮助。 utf8::upgrade returns a number of octets,在对字符串进行就地操作后。如果您将其保留为:

    $object = decode("utf-8", $object);
    

    那么你可能会有更容易理解的行为。

    我想在这个简短的脚本的帮助下我想出了更多:

    #! /usr/bin/perl -w
    use Encode;
    binmode( STDOUT, ":utf8" );
    my $string = "\x{C3}\x{B6}";
    print "$string\n";
    my $decoded = decode( "UTF8", $string );
    print "$decoded\n";
    

    输出是:

    ö
    ö
    

    这就是我认为正在发生的事情。上面的 $string 声明是您从调用 cgi->param 中得到的,即在 UTF-8 中表示 ö 的两个字节。当脚本第一次打印它时,Perl 没有任何迹象表明这是 UTF-8,但知道它必须在打印之前先转换它(因为 bin 模式)。

    Perl 的默认行为是假设要解释为字符串的八位字节流被编码为 Latin-1。所以它需要第一个字节 C3,查找它在 Latin-1 中的内容,然后打印相当于 STDOUT 的 UTF-8。 B6 也一样。您可以仔细检查Wikipedia 上的字节。

    但是,对 decode 的调用会将字节解释为 UTF-8 并创建一个由字符 ö 组成的新字符串。不要将字符串视为具有编码;传入和传出的字节需要编码,但在您的程序中,一旦它们被正确解释,它们就只是字符串。

    现在 Perl 已经解释了这些字节并转换为使用它希望的任何内部编码进行编码的字符串,当你下次打印它时,它知道将字符转换为 UTF-8 并且你得到正确的输出。

    希望对调试 CGI 有所帮助。

    【讨论】:

    • 感谢您的快速回复!
    猜你喜欢
    • 2015-11-08
    • 1970-01-01
    • 1970-01-01
    • 2011-08-25
    • 2017-03-16
    • 1970-01-01
    • 1970-01-01
    • 2023-03-23
    • 1970-01-01
    相关资源
    最近更新 更多