Perl cgi和XML :: Code双重编码问题

时间:2012-10-07 12:09:11

标签: xml perl utf-8 cgi

我正在使用XML :: Code从通过CGI模块接收的GET参数创建一些XML数据。 Web服务器是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库中的错误还是我的想法?

最佳, 马库斯

1 个答案:

答案 0 :(得分:0)

我认为以下一行:

$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-&gt; param回来的,也就是说它是两个字节,表示UTF-8中的ö。当脚本首次打印时,Perl没有迹象表明它是UTF-8,但是知道必须先打印它才能打印(因为binmode)。

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

然而,对decode的调用会将字节解释为UTF-8并创建一个由字符ö组成的新字符串。不要认为字符串有编码;进出的字节需要一个编码,但在你的程序中,一旦它们被正确解释,那么它们只是字符串。

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

希望能帮助您调试CGI。