同じ freebsd システムの新しいホスティング プロバイダに移行しましたが、perl スクリプトの 1 つが正しく動作しなくなりました。
外部の 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->decoded_content() を $res->content() に置き換えると、すべてが機能します。おそらく、ダウンロードしているページのヘッダーに文字セットがないためです。
cp1251 のように見えますが、そうではないというような方法で、decoded_content がどのように文字列を台無しにするのか、私はまだ理解していません。多分いくつかの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}
);
}
}
}