我已经迁移到具有相同 freebsd 系统的新托管服务提供商,并且我的一个 perl 脚本停止正常工作。
它从外部 https 站点下载数据并将其存储在 mysql db 中。数据采用 cp1251 编码,mysql 基础、表和连接中的编码相同。来自 my.cnf:
character-set-server=cp1251
collation-server=cp1251_general_ci
init-connect="SET NAMES cp1251"
从 perl 脚本连接到 mysql 时:
$dbh->do('SET CHARACTER SET cp1251');
所以,我得到这个数据
$ua = new LWP::UserAgent;
....
$res = $ua->get(....)
$s = $res->decoded_content();
然后脚本将解析这个 $s 并将结果插入 mysql。当它发生时,编码被破坏!
我发现有趣的是,如果我只是将这些数据写入一个文本文件,然后从这个文件中读取它并将其插入 mysql - 它没有损坏!
当我查看此文本文件时,我看到数据采用 cp1251 编码。
自上次托管以来发生了什么变化:
perl:从 5.10.1 到 5.14.4
libwww:从 5.835 到 6.05
mysql服务器是一样的5.1
更新:哇,刚刚发现了一些东西。如果我用 $res->content() 替换 $res->decoded_content(),一切正常。也许那是因为我正在下载的页面的标题中没有字符集。
我仍然不明白 decoded_content 如何以这种方式与字符串混淆,它看起来像 cp1251 但事实并非如此。一些 utf 标志可能吗?帮助请。
UPDATE2:这是脚本(主要部分):
#!/usr/bin/perl
use POSIX qw(strftime);
use LWP::UserAgent;
use HTTP::Headers;
use HTTP::Cookies;
use Digest::MD5 qw(md5_hex);
use DBI;
use common::sense;
no utf8;
no strict;
$ua = new LWP::UserAgent;
$hh = HTTP::Headers->new(
User-Agent => 'Mozilla/5.0 (Windows NT 5.1; rv:21.0) Gecko/20100101 Firefox/21.0',
Accept => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
Accept-Language => 'en-us,en;q=0.7,ru;q=0.3',
Accept-Encoding => 'gzip, deflate',
Connection => 'keep-alive',
);
$ua->default_headers( $hh );
$ua->cookie_jar({});
$ua->timeout(20);
YMoney();
sub YMoney {
$res = $ua->get('...');
$res = $ua->post('...');
...
$res = $ua->get("...");
$s = $res->decoded_content();
@list = reverse split("\n", $s);
$dbh = DBI->connect("DBI:mysql:database=orders;host=localhost;port=3306", ....);
$dbh->do('SET CHARACTER SET cp1251');
for $line (@list) {
next if ($line !~ /^\+;/);
@pay{'data', 'amount', 'comment'} = map { s/"+//g; $_ } (split(';', $line))[1, 2, 5];
$pay{hash} = md5_hex( join('', @pay{'data', 'amount', 'comment'}) );
$id = $dbh->selectrow_array("SELECT id FROM ymoney WHERE hash = ?", {}, $pay{hash});
if (!$id) {
$dbh->do("INSERT INTO ymoney (operator, hash, data, amount, comment) VALUES ('yandex', ?, ?, ?, ?)", {},
$pay{hash}, DB_Date($pay{data}), DB_Amount($pay{amount}), $pay{comment}
);
}
}
}