Автор Тема: UTF-8 и URL encoding (x-www-form-urlencoded)  (Прочетена 3451 пъти)

vstoykov

  • Участник
  • *****
  • Публикации: 1286
  • Distribution: Ubuntu
  • Window Manager: Fluxbox
    • Профил
    • WWW
UTF-8 и URL encoding (x-www-form-urlencoded)
« -: Яну 10, 2006, 21:08 »
Имам проблеми със следния скрипт на Perl със CGI интерфейс:

Примерен код

#!/usr/bin/perl
#*************************************************************************
#
# Програма за конвертиране на шльокавица към кирилица
# Copyleft (C) 2005 Валентин Стойков <http://vstoykov.hit.bg/>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
#*************************************************************************

#*************************************************************************

use locale;
use encoding 'utf8';
use utf8;

#require("/home/valentin/62c/modulelat2cyr.pm");
require("/home/vslivecd/62c/modulelat2cyr.pm");
#require("/usr/share/62c/modulelat2cyr.pm");

#*************************************************************************

my $in;
if ($ENV{'REQUEST_METHOD'} eq "GET") {
   $in = $ENV{'QUERY_STRING'};
}
else {
  $in = <STDIN>;
}

sub strToHTML {
  my $text = shift;
  $text =~ s|\&|\&amp\;|g;
  $text =~ s|\"|\&quot\;|g;
  $text =~ s|<|\&lt\;|g;
  $text =~ s|>|\&gt\;|g;
  return $text;
}


print <<EOT;
Content-type: text/html

<html>
<head>
<title> Превод на шльокавица </title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<style>
</style>
</head>
<body>

<table align="center" BORDER=0 CELLSPACING=0 CELLPADDING=0 height="100%" width="100%">
<tr align="center"><td align="center">

EOT

if ($in ne "") {

print   <<EOT;

<textarea cols=80 rows=15 style="font-size: 14pt; background: #98add5">
EOT

$in =~ tr/+=/ &/d;
chomp($in);
my %input = split(/&/,$in);
$input_data=$input{"latinica"};
# Un-Webify plus signs and %-encoding
$input_data =~ tr/+/ /;
$input_data =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
$line=convert_line_lat2cyr($input_data);
print strToHTML($line);

print   <<EOT;
</textarea>

EOT

}

else {
print   <<EOT;

<form action="form.pl" method="post">

<textarea name=latinica cols=80 rows=15 style="font-size: 14pt; background: #98add5">
</textarea>
<br>
<INPUT type=submit value=" Изпрати ">&nbsp;<INPUT type=reset value=" Изчисти ">
</form>

EOT


}


print   <<EOT;

</td></tr>
</table>


</body>
</html>

EOT



Проблемът се наблюдава, когато в бланката (формата) се попълни текст на кирилица. След конвертирането текстът, който е бил на кирилица се вижда на маймуни, а текстът на латиница се вижда на кирилица (каква ирония... шльокавицата да се чете нормално, а кирилицата - не).

Струва ми се, че проблемът е в този ред:
Примерен код

$input_data =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;


Пробвай най-различни варианти, но не се получава:

Примерен код

$input_data =~ s/%([a-fA-F0-9][a-fA-F0-9])%(([a-fA-F0-9][a-fA-F0-9]))/pack("U", hex($1.$2))/eg;
$input_data =~ s/%([a-fA-F0-9][a-fA-F0-9])%(([a-fA-F0-9][a-fA-F0-9]))/chr(hex($1.$2))/eg;

$input_data =~ s/%([a-fA-F0-9][a-fA-F0-9])%([a-fA-F0-9][a-fA-F0-9])/pack("U", hex($1."00"), hex($2))/eg;
$input_data =~ s/%([a-fA-F0-9][a-fA-F0-9])%([a-fA-F0-9][a-fA-F0-9])/pack("U", hex($1.$2))/eg;
$input_data =~ s/%([a-fA-F0-9][a-fA-F0-9])%([a-fA-F0-9][a-fA-F0-9])/$1.$2." "/eg;
$input_data =~ s/%([a-fA-F0-9][a-fA-F0-9])%([a-fA-F0-9][a-fA-F0-9])/"1=".$1." 2=".$2."  "/eg;
$input_data =~ s/%([a-fA-F0-9][a-fA-F0-9])%([a-fA-F0-9][a-fA-F0-9])/$1.$2."  "/eg;
$input_data =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("a", hex($1))/eg;
$input_data =~ s/%([a-fA-F\d]+)/chr(hex($1))/ge;



Търсенето с Google не доведе до резултати.
Активен

  • Гост
UTF-8 и URL encoding (x-www-form-urlencoded)
« Отговор #1 -: Яну 11, 2006, 00:55 »
Честно казано набързо прегелдах поста и не съм се задълбочовал много, но ти пращам изпозваното при мене решение:

Примерен код

sub URL_decode
{
  my $url = $_[0];
  $url =~ tr/+/ /;
  $url =~ s/%([a-fA-F0-9]{2,2})/chr(hex($1))/eg;
  $url =~ s/<!--(.|\n)*-->//;
  return $url;
}

$url_param =~ s/([;<>\*\|`&\$!?#\(\)\[\]\{\}:'"\\])/\\$1/g;

Активен

vstoykov

  • Участник
  • *****
  • Публикации: 1286
  • Distribution: Ubuntu
  • Window Manager: Fluxbox
    • Профил
    • WWW
UTF-8 и URL encoding (x-www-form-urlencoded)
« Отговор #2 -: Яну 11, 2006, 18:20 »
Твоето решение предполагам, че работи идеално на cp1251, но при мен не става. Ползвам UTF-8. Например "абв" при мен излглежда така "%D0%B0%D0%B1%D0%B2". За всяка буква има по два байта.
Активен

vstoykov

  • Участник
  • *****
  • Публикации: 1286
  • Distribution: Ubuntu
  • Window Manager: Fluxbox
    • Профил
    • WWW
UTF-8 и URL encoding (x-www-form-urlencoded)
« Отговор #3 -: Яну 11, 2006, 18:28 »
При опит с това:
Примерен код
$input_data =~ s/%([a-fA-F0-9][a-fA-F0-9])%([a-fA-F0-9][a-fA-F0-9])/pack("U", hex($1.$2))/eg;

след конвертиране връща три квадрата с числа в тях:
http://d.interbild.net/vstoykov/tmp/bugs/62c/abv_code.png
Обърнете внимание на това, че числата съответстват на кодовете на буквите. Не виждам причина да се появяват квадрати вместо букви...
Същото се получава и в този случай:
Примерен код
$input_data =~ s/%([a-fA-F0-9][a-fA-F0-9])%([a-fA-F0-9][a-fA-F0-9])/chr(hex($1.$2))/eg;


Не ми се иска интерфейсът да е на cp1251 и вътрешно да се прави конвертиране на UTF-8 (грозно е и няма да работи с букви различни от кирилицата и латиницата - не че на някой ще му трябва, но не е хубаво да се пише калпав софтуер - то и през миналия век не им е трябвало повече от 7 бита/символ за кодиране на текст...).
Активен

  • Гост
UTF-8 и URL encoding (x-www-form-urlencoded)
« Отговор #4 -: Яну 11, 2006, 19:35 »
не съм в час с perl, но
Примерен код
use locale;
use encoding 'utf8';
use utf8;....

Не видях да се задава local и си мисля си дали той не е "C" ("POSIX"), когато се изпълнява скрипта ?
Пробвал ли си да зададеш изрично en_US.UTF-8 ?
Активен

vstoykov

  • Участник
  • *****
  • Публикации: 1286
  • Distribution: Ubuntu
  • Window Manager: Fluxbox
    • Профил
    • WWW
UTF-8 и URL encoding (x-www-form-urlencoded)
« Отговор #5 -: Яну 11, 2006, 20:33 »
Махнах този ред:
Примерен код

use encoding 'utf8';

от файловете form.pl и modulelat2cyr.pm и проблемът се реши.
Все още не съм много наясно какво точно се получава, но щом работи - добре е.
Активен

vstoykov

  • Участник
  • *****
  • Публикации: 1286
  • Distribution: Ubuntu
  • Window Manager: Fluxbox
    • Профил
    • WWW
UTF-8 и URL encoding (x-www-form-urlencoded)
« Отговор #6 -: Яну 11, 2006, 21:04 »
Оказа се, че на друга машина не работи както на моята.
Тук може да тествате програмата за превод от шльокавица към кирилица:

http://vslivecd.openfmi.net/perl/form.pl
Активен

CaBA

  • Участник
  • *****
  • Публикации: 303
    • Профил
    • WWW
UTF-8 и URL encoding (x-www-form-urlencoded)
« Отговор #7 -: Яну 12, 2006, 14:09 »
Примерен код
#!/usr/bin/perl -C

Цитат
-C [number/list]
            The "-C" flag controls some Unicode of the Perl Unicode features.

            As of 5.8.1, the "-C" can be followed either by a number or a list of option letters.  The letters, their
            numeric values, and effects are as follows; listing the letters is equal to summing the numbers.

                I     1    STDIN is assumed to be in UTF-8
                O     2    STDOUT will be in UTF-8
                E     4    STDERR will be in UTF-8
                S     7    I + O + E
                i     8    UTF-8 is the default PerlIO layer for input streams
                o    16    UTF-8 is the default PerlIO layer for output streams
                D    24    i + o
                A    32    the @ARGV elements are expected to be strings encoded in UTF-8
                L    64    normally the "IOEioA" are unconditional,
                           the L makes them conditional on the locale environment
                           variables (the LC_ALL, LC_TYPE, and LANG, in the order
                           of decreasing precedence) -- if the variables indicate
                           UTF-8, then the selected "IOEioA" are in effect

            For example, "-COE" and "-C6" will both turn on UTF-8-ness on both STDOUT and STDERR.  Repeating letters is
            just redundant, not cumulative nor toggling.

            The "io" options mean that any subsequent open() (or similar I/O operations) will have the ":utf8" PerlIO layer
            implicitly applied to them, in other words, UTF-8 is expected from any input stream, and UTF-8 is produced to
            any output stream.  This is just the default, with explicit layers in open() and with binmode() one can manipu&#8208;
            late streams as usual.

            "-C" on its own (not followed by any number or option list), or the empty string "" for the "PERL_UNICODE"
            environment variable, has the same effect as "-CSDL".  In other words, the standard I/O handles and the default
            "open()" layer are UTF-8-fied but only if the locale environment variables indicate a UTF-8 locale.  This
            behaviour follows the implicit (and problematic) UTF-8 behaviour of Perl 5.8.0.

            You can use "-C0" (or "0" for "PERL_UNICODE") to explicitly disable all the above Unicode features.

            The read-only magic variable "${^UNICODE}" reflects the numeric value of this setting.  This is variable is set
            during Perl startup and is thereafter read-only.  If you want runtime effects, use the three-arg open() (see
            "open" in perlfunc), the two-arg binmode() (see "binmode" in perlfunc), and the "open" pragma (see open).

            (In Perls earlier than 5.8.1 the "-C" switch was a Win32-only switch that enabled the use of Unicode-aware
            "wide system call" Win32 APIs.  This feature was practically unused, however, and the command line switch was
            therefore "recycled".)
Активен

10 години ябълкова диета стигат, стигат!

  • Гост
UTF-8 и URL encoding (x-www-form-urlencoded)
« Отговор #8 -: Яну 12, 2006, 18:33 »
Нещо се съмнявам че идеята ще стработи.
tr функцията, ако следва поведението на командата, засега няма да стане:
Примерен код
$ echo АБВАБВ | sed -e 's|А|x|g' -e 's|Б|y|g'
xyВxyВ
$ echo АБВАБВ | tr АБВ xyz
zyzzzzzyzzzz
$ locale charmap
UTF-8

Бел.: в примера по-горе символите с главни букви са на кирилица !
А sed създава измамно впечатление, че работи !
Сигурно ли е, че tr и s в perl разбират от UTF-8 ?


"use locale;" не ми изглежда подходящо за web. Кой ще подаде на скрипта променливите като LANG LC_CTYPE LC_ALL :
- първо трябва да са установени в обкръжението на процеса, които стартира web сървера;
- после май трябва изрично да се укаже, кои променливи, да се предават на CGI;
- а ако скрипта се стартира през mod_perl - да се види как се предават

Администрирането на такава система става много сложно!

Затова,  в web приложение, моето предложение е да се ползва     setlocale(..., "xx_YY.UTF_8") и да не се разчита на настройките на сървера и неговото обкръжение. Моето мнение е, че демоните и root трябва да работят без езикови настройки или в "C" ("POSIX").


Не трябва да се забравя, че символите в UTF-8 са с променлива дължина - от един до шест байта. Функциите tr и s, май, просто заменят поредици от байтове и оттук е моя скептицизим, че с тях  може да се реши задачата. В решението трябва да се използва алгоритъм за обработка на символи.
Бел.: символ != байт
Поредица от байтове като "0xD0 0xD0 0xB0" не е валидна UTF-8 последователност от символи.


Може би трябва да се помисли за решение с iconv.
Нещо такова:
- конвертира се с iconv входния поток от UTF-8 в KOI-8
- някакви специфични пудри с латинските символи: например sh да стане ш на кирилица
- вдига се 8-мия бит на останалите латинските символи
- превръщане с iconv от KOI8-R в UTF-8
Незнам да ли ще удачно, понеже имам спомени от предишни дискусии, че имаше варианти, например от 'sh' в 'ш' или 'сх'.


Би трябвало да може и без iconv, но входния поток трябва да се обработва utf8-символ по utf8-символ.
Активен

vstoykov

  • Участник
  • *****
  • Публикации: 1286
  • Distribution: Ubuntu
  • Window Manager: Fluxbox
    • Профил
    • WWW
UTF-8 и URL encoding (x-www-form-urlencoded)
« Отговор #9 -: Яну 12, 2006, 23:09 »
Струва ми се, че успях да подкарам програмата на cp1251:
http://vslivecd.openfmi.net/perl/form1251.pl
В началото на form.pl и modu..1251.pl сложих:
Примерен код

use encoding 'cp1251';


Тук са скриптовете:
http://vslivecd.openfmi.net/62c/

Кеша на браузъра ми ли прави проблеми... един път програмата  работи - следващия не... Или може би причината е другаде  - когато съм се логнал през ssh към машината, където е сървъра - работи, когато изляза - спира да работи..
Активен

vstoykov

  • Участник
  • *****
  • Публикации: 1286
  • Distribution: Ubuntu
  • Window Manager: Fluxbox
    • Профил
    • WWW
UTF-8 и URL encoding (x-www-form-urlencoded)
« Отговор #10 -: Апр 10, 2006, 21:23 »
Вече работи.
Демонстрация:
http://vslivecd.openfmi.net/cgi-bin/form.pl
http://vslivecd.openfmi.net/cgi-bin/form1251.pl

При втория вариант обработката главни/малки букви е по-добре, но има какво да се желае.

Магията стана по следния начин:

За варианта с кодиране "UTF-8":
Примерен код

#use locale; # този ред е коментиран
#use encoding 'utf8'; # този ред създава проблеми!
#use utf8; # този ред е коментиран
use POSIX qw(locale_h);
setlocale(LC_ALL, "bg_BG.UTF-8");


За варианта с кодиране "cp1251":
Примерен код

use encoding 'cp1251';
use POSIX qw(locale_h);
setlocale(LC_ALL, "bg_BG.CP1251");


Архив:
http://vslivecd.openfmi.net/62c/62c-10042006.4.tar.bz2
http://vslivecd.openfmi.net/62c/62c-10042006.4.tar.bz2.md5
Активен

Подобни теми
Заглавие Започната от Отговора Прегледи Последна публикация
default encoding in KDE
Настройка на програми
rat 4 1565 Последна публикация Сеп 18, 2003, 17:23
от alabal
Sqwebmail encoding problem
Настройка на програми
desinikolova 3 1430 Последна публикация Мар 13, 2005, 22:08
от rpetrov
Кирилица за напреднали (encoding interoperability)
Хардуерни и софтуерни проблеми
RABBIT 6 2804 Последна публикация Яну 05, 2006, 10:47
от RABBIT
Encoding-a в apache2 ?
Web development
aReS 5 1988 Последна публикация Мар 09, 2006, 01:17
от steady
Encoding
Живота, вселената и някакви други глупости
luda_glawa 19 4532 Последна публикация Окт 26, 2006, 02:36
от SOMNIVM