
Смена кодировки сайта на perl'e с window-1251 на utf8. Продолжение...
Описанный ранее автоматический способ перевода сайта на perl'e с виндовской кодировки в юникод разбился об реальность %). Опишу проблемы, с которыми пришлось столкнуться, может быть кому-то пригодится.
1. База данных. В моем случае - это mysql. У каждого скаляра, вынутого из базы данных, должна стоять галочка, что он в utf8. В противном случае не будут работать regexp'ы и проч. Можно помечать их utf8-ом руками:
utf8::decode($string_from_db);
Но если применить это к двоичным данным из blob'ов, то что-нибудь может сломаться. Альтернативный вариант - это после соединения с БД сообщить DBI, что данные в utf8.
$dbh->{'mysql_enable_utf8'} = 1 if($encoding=~/utf/i);
Тогда она должна сама переводить строки в utf8, а blob не трогать. Должна, но на хостинге у nic.ru почему-то то работает, то не работает. Вроде бы в третьей DBI были какие-то косяки с utf8.
Вот не очень красивый, но эффективный способ это полечить:
my $rusletters = qr{А-Яа-я}; #... # для всего, что вытаскивается из бд _fix_utf8($data_from_db); #... # если кодировка utf8, то # у все, что вытаскивается из БД, нужено пометить, как utf8 sub _fix_utf8 { my $arg = shift; # return $arg; #!! off return undef unless ( defined $arg ); return $arg unless ( $encoding =~ /utf/i ); unless ( ref $arg ) { utf8::decode( $arg ) if (utf8::valid($arg) and !utf8::is_utf8( $arg ) and $arg=~$rusletters); return $arg; } elsif ( ref $arg eq "ARRAY" ) { return _fix_utf8_array($arg); } elsif ( ref $arg eq "HASH" ) { die "hash?"; return _fix_utf8_hash($arg); } return $arg; } sub _fix_utf8_array { my $arg = shift; return $arg unless ( ref $arg eq "ARRAY" ); for ( my $i = 0 ; $i < 1 + $#$arg ; $i++ ) { $arg->[$i] = _fix_utf8_array( $arg->[$i] ) if ( ref $arg->[$i] eq "ARRAY" ); $arg->[$i] = _fix_utf8( $arg->[$i] ) unless ( ref $arg->[$i] ); } return $arg; }
Он помечает utf-8 все строки, которые не помечены utf8, и содержат буквы А-Яа-я в юникоде. В общем-то в буквах А-Яа-я вся некрасивость.
2. Во всех модулях, где в качестве значения переменных используется utf-8, надо писать
use utf8; #... $param->{ModuleName}="Блог";
Тоже самое, если в модуле выполняются regexp'ы над юникодными строками.
3. Всех параметры http-запросов, кроме файлов, надо декодить в utf8, например так:
foreach ( $self->{httprequest}->param ) { utf8::decode($k); if ( $v && !( ref $v && fileno($v) ) ) { $k =~ s/\.x//go; next if ( $k =~ /\.y/ ); utf8::decode($v); } $self->{entry}->{$k} = $v;
4. Отправку писем в utf8 тоже пришлось переписать. Подробности в предыдущем посте.
5. Пришлось поправить модуль DBIx::FullIndexSearch. Кому надо, пишите, выложу.
6. При открытии файлов надо указывать, что они в utf8:
open my $fh, '<:utf8', $tname or die $!;