[linux] phpmyadmin +kodovanie - nastavenie kodovania pre MySQL

Lubomir Host rajo na platon.sk
Pondělí Duben 10 10:23:50 CEST 2006


On Fri, Apr 07, 2006 at 01:53:39PM +0200, michal.lackovic na sk.non.schneider-electric.com wrote:
> toto som vyflusol z moje databazy:
> Server version:         5.0.18
> Protocol version:       10
> Connection:             Localhost via UNIX socket
> Server characterset:    latin1
> Db     characterset:    latin1
> Client characterset:    latin1
> Conn.  characterset:    latin1
> 
> Zvlastne ale je,ze clanky ktore som importoval z mysql admina sa za 
> zobrazuju spravne na stranke ktora ma nastavene kodovanie cp1250.
> Avsak vsetko co vlozim cez myphpadmin sa nezobrazi spravne. Co teda 
> nastavit?
> dakujem
> miso

Z casovych dovodov iba preposielam tuto do konfery relativne dlhy ale hadam
aj poucny sukromny e-mail. Snad som nezabudol nic privatne vyhodit.

Dufam, ze to pomoze pri rieseni problemov s nastavovanim kodovania
v MySQL. Nadalej plati, ze na korektne vyriesenie problemu je ziaduce
plne pochopit problematiku nastavovania kodovania v MySQL a preto uz
nebudem z pochopitelnych odpovedat na otazky, ktore sa daju vycitat
z manualu. Preto aj tento mail neberte ako plnohodnotne riesenie vasho
problemu, ale skor ako navod, ako by sa to malo spravne robit.

Btw. pouzivam rovnaku verziu MySQL az na tie nastavenia. Vsetky default
charsety mam utf8.

Dakujem za pochopenie.

S pozdravom Lubomir Host

----- Forwarded message from Lubomir Host <rajo na platon.sk> -----

> Date: Wed, 22 Feb 2006 16:01:46 +0100
> From: Lubomir Host <rajo na platon.sk>
> To: protected na privacy.sk
> Subject: nastavenie kodovania v MySQL
> 
> Zdravim,
> 
> ja som dnes riesil podobny problem u nas vo firme. Ale celu vec som mal
> komplikovanu tym, ze mame 3 rozne MySQL servery v roznych verziach
> a nastavene rozne. Takisto weby mame vo windows-1250 (alias cp1250), ale
> nove weby chceme mat UTF-8. Okrem toho tie weby zdielaju spolocny
> databazovy modul a databazove tabulky, voci ktorym sa robi
> autentifikacia uzivatelov (dost premakana, takze nechcem mat duplicitny
> kod v kazdom projekte). Cize v podstate ten isty web musi vediet
> pracovat s tabulkami aj v UTF-8 aj vo windows-1250. Ufff, podarilo sa
> to. Popisem ako:
> 
> Verzie MySQL su nasledovne:
> 
> 4.0.22 - default cp1250, produkcny, je mu dost jedno, ake kodovanie maju data
> 4.1.12 - default cp1250, devel
> 5.0.18 - default UTF-8, devel
> 5.0.x  - planovany novy produkcny server, ktory bude UTF-8
> 
> Najprv import dat z produkcneho 4.0.x na devel servery >4.1.x:
> 
> - spravi sa klasicky MySQL dump, ktory neobsahuje ziadnu definiciu
>   charsetov.
> 
> - pri importe sa na zaciatok dumpu predradi toto kuzelne slovicko:
> 
> ----------------------------------%<----------------------------------
>   (
>     echo '/*!40101 SET CHARACTER_SET_CLIENT=cp1250 */;' ; cat dump.sql
>   ) | mysql -u developer -h devel.server.sk
> ----------------------------------%<----------------------------------
> 
>   Funguje to, lebo data na produkcnom serveri naozaj v takom kodovani
>   su, len to tam v dumpe napisane nikde nie je.
> 
> Teraz perlovy kod. Tento kod musi byt univerzalny, aby som sa uz nemusel
> starat o to, na ktory server sa pripajam, ako tam su nastavene
> mysql-defaults a aka verzia mysql na serveri je. Nesmiem zabudnut na to,
> ze nove projekty uz budu UTF-8, takze v databazovom module musim mat
> sancu povedat, ake kodovanie chcem. Preto po pripojeni bezia nasledovne
> prikazy:
> 
> -------------------------------%<-------------------------------
> my $charset     = $globals::dbCharset || 'cp1250';
> my $collation   = $globals::dbCollation || 'cp1250_general_ci'; 
> 
> $dbh->do("/*!40101 SET NAMES $charset */");
> $dbh->do("/*!40101 SET COLLATION_CONNECTION=$collation */");
> -------------------------------%<-------------------------------
> 
> ... cize ak ma novy projekt v $globals::dbCharset nastavenu znakovu sadu
> nejaku, pouzije sa ta, inac je to default 'cp1250' (pre stare projekty).
> To iste s collation. Vid este tie komentare, aby to zbehio aj na
> produkcom serveri 4.0.22.
> 
> Teraz este autentifikacna kniznica: tu je problem, ze kodovanie tychto
> starych autentifikacnych tabuliek moze byt ine, ako klient pouziva
> pri komunikacii s DB. Objavil som problem v selectoch, ktore pouzivaju
> funkciu FIND_IN_SET(). V niektorych pripadoch ten select musi vyzerat takto:
> 
> ----------------------------------%<----------------------------------
>     /* autentifikaciau uzivatela */
>      SELECT  
>              u.uid, u.alias, u.sluzba
>      FROM Users AS u
>      WHERE u.active = 1
>              AND u.valid_from < NOW() AND u.valid_to > NOW()
>              AND (u.sluzba = '' OR FIND_IN_SET('myservice', u.sluzba) > 0)
>              AND u.alias = 'rajo'
>              AND u.password = PASSWORD('******')
> ----------------------------------%<----------------------------------
> 
> A niekedy takto (vid ten CONVERT( ... USING utf8)):
> 
> --------------------------------------------%<--------------------------------------------
>     /* autentifikaciau uzivatela */
>      SELECT  
>              u.uid, u.alias, u.sluzba
>      FROM Users AS u
>      WHERE u.active = 1
>              AND u.valid_from < NOW() AND u.valid_to > NOW()
>              AND (u.sluzba = '' OR FIND_IN_SET('myservice', CONVERT(u.sluzba USING utf8)) > 0)
>              AND u.alias = 'rajo'
>              AND u.password = PASSWORD('******')
> --------------------------------------------%<--------------------------------------------
> 
> - autentifikacny modul si z databazy vycucne, akej verzie je server
>   a ake kodovania su nastavene. Robi sa to iba pri starte aplikacie a to zhruba nasledovne:
> 
> ----------------------------------------------%<----------------------------------------------
>     # Tato prva cast kodu vyrobi iba taky hash, kde klucom je nazov premennej a hodnotou
>     # jej obsah. Zhruba takto:
>     #
>     #       'character_set_connection' => 'utf8'
>     #       'character_set_client' => 'utf8',
>     #       'character_set_results' => 'utf8',
>     #       'character_set_system' => 'utf8',
>     #       'character_set_server' => 'cp1250',
>     #       'character_set_database' => 'cp1250',
>     #       'character_sets_dir' => '/usr/local/mysql-max-4.1.12-pc-solaris2.10-i386/share/mysql/charsets/',
>     #       'version' => '4.1.12-max-log',
>     #       'version_compile_machine' => 'i386',
>     #       'version_compile_os' => 'pc-solaris2.10',
>     #       'version_comment' => 'MySQL Community Edition - Experimental (GPL)',
>     #       'version_bdb' => 'Sleepycat Software: Berkeley DB 4.1.24: (May 10, 2005)',
>     #
>     my $char_var;
>     my $xx_char_var = [
>         @{ $dbh->selectall_arrayref("SHOW VARIABLES LIKE 'version%'") }, 
>         @{ $dbh->selectall_arrayref("SHOW VARIABLES LIKE 'character%'") }, 
>     ]; 
>     foreach my $entry (@$xx_char_var) {
>         $char_var->{$entry->[0]} = $entry->[1];
>     }  
> 
>     # a teraz na zaklade tychto parameterov, ktore zistil, sa rozhodne, ako bude obalovat
>     # to vkladanie parametru do FIND_IN_SET() funkcie
>     # robi to iba pre MySQL > 4.1.x, lebo 4.0 nepozna funkciu CONVERT()
>     if ($char_var->{version} =~ m/^(4\.1|5)/ 
>         and defined $char_var->{character_set_server}
>             and ($char_var->{character_set_server} ne $char_var->{character_set_client}
>                 or $char_var->{character_set_server} ne $char_var->{character_set_connection}
>         )) {
> 
>         $self->{_convert} = sub {
>             my ($string) = @_;
>             my $charset = $globals::dbCharset || 'cp1250';
>             return "CONVERT($string USING $charset)";
>         }; 
> 
>     }  
>     else {
>         $self->{_convert} = sub { return shift; }; 
>     }  
> ----------------------------------------------%<----------------------------------------------
> 
> Pri vytvarani selectov do DB uz potom iba volam:
> 
> -----------------------------------------------------------%<-----------------------------------------------------------
>     $self->{sql_auth_user_login} = $dbh->prepare(" /* sql_auth_user_login " . __FILE__.':'.__LINE__ . " */
>         SELECT 
>             u.$self->{users_id_col}, u.$self->{users_alias_col}, u.$self->{service_col}
>         FROM $self->{db_user_table} AS u
>         WHERE u.active = 1
>             AND u.$self->{users_valid_from_col} < NOW() AND u.$self->{users_valid_to_col} > NOW()
>             AND (u.$self->{service_col} = ''
>                     OR
>                  FIND_IN_SET('$globals::sluzba' /* value */, " . &{$self->{_convert}}("u.$self->{service_col}") . ") > 0
>             )
>             AND u.$self->{users_alias_col} = ?
>             AND u.password = PASSWORD(?)
>     ") or croak "Can't get user: " . $dbh->errstr;
> -----------------------------------------------------------%<-----------------------------------------------------------
> 
> $self je ten autentifikacny objekt a $self->{users_id_col},
> $self->{users_valid_from_col} su nazvy stlpcov a tabuliek pre tu
> instanciu. To kvoli tomu, pretoze tento autentifikacny modul sa da
> pouziat aj nad tabulkami s inymi nazvami a inymi nazvami stlpcov. Pfuj,
> dobre obfuscovany kod. ;-)
> 
> &{$self->{_convert}}("nejaky_nazov_stlpca") teda pri pripravovani
> selectu zavola funkciu (ktoru som dynamicky vytvoril pri inicializacii
> objektu) a ta vrati bud retazec "nejaky_nazov_stlpca" pre mysql <4.1.x
> alebo retazec CONVERT(nejaky_nazov_stlpca USING $kodovanie_klienta).
> Inac by to skoncilo s chybou:
> 
> Illegal mix of collations (utf8_general_ci,COERCIBLE) and
> (cp1250_general_ci,IMPLICIT) for operation 'find_in_set'
> 
> Dolezite je to, ze vsetky tieto pomocne funkcie su volane iba raz a ten
> select uz mam preparnuty na vykonavanie kolko krat chcem. Toto je
> vlastnost DBI modulu (vid $dbh->prepare()) a toto tusim PHP kniznice na
> pracu s DB nevedia. Za znak '?' sa zasubstituuje patricna hodnota
> a samozrejme sa spravi escape na apostrofy a ine zle znaky. Cize SQL
> injection chyba nehrozi.
> 
> Ufff, nejako som sa rozpisal. ;-) Ale to uz by snad bolo vsetko, dalsie
> poznamky v skratke dole.


> >     $set = @mysql_query ('SET NAMES CP1250');
> >     $set = @mysql_query ('SET COLLATION_CONNECTION=CP1250_GENERAL_CI');
> 
> V kode by si to este mohol vylepsit tym, ze prikazy zaobalis do
> komentara "/*!40101 ... */" a bude ti to fungovat aj u klientov, ktori
> by mali 4.0.x databazu.
>
> > CIZE SUMA SUMMARUM: kodovanie databazovych tabuliek musi byt zhodne
> > s kodovanim pripojenia (connection). Ak je to zhodne, je jedno ake
> > kodovanie to je, proste to funguje. Zato nam funguje aj riereal.sk/demo
> > aj fiora.sk pricom oba weby idu s windows-1250 kodovanim, ale databazovy
> > backend fiora.sk je latin1 (toto je default pre connection) a backend
> > riereal.sk/demo je windows-1250 (cp1250).
> 
> Toto nie je uplne pravda. Mozes mat tabulky v roznom kodovani (dokonca
> aj stlce v jednej tabulke mozu mat rozne), ale klient musi tieto data
> posielat kodovane spravne a musi to suhlasit s tym, ako je nastavene
> character_set_client. MySQL to prekoduje podla potreby.
> 
> > Pre uplnost: ci toto riesi problemy s vadnymi dumpami z phpMyAdminu
> > neviem, ale skor nie ako ano. Totiz tie vadne dumpy su na beton chyba
> > phpMyAdminu, ale neboj, vyriesime aj to. On tam totiz stale drbe to
> > UTF-8, tj dostanes dump v UTF-8 ale ten debilneho soft nenapise do
> > hlavicky ze je to UTF-8. Ty koncis s tym, ze do svojho lokalneho MySQL
> > davas UTF-8 dump, pricom server si mysli, ze je to windows-1250.
> > Pekna dzungla.
> 
> Ano, vyzera to byt chyba phpMyAdminu a on by to mal nastavovat. Ale
> podrobnejsie som tie dupy neanalyzoval.
> 
> rajo
> 
> -- 
> Lubomir Host 'rajo' <rajo AT platon.sk>   ICQ #:  257322664   ,''`.
> Platon Group                              http://platon.sk/  : :' :
> Homepage: http://rajo.platon.sk/                             `. `'
> http://www.gnu.org/philosophy/no-word-attachments.html         `-

----- End forwarded message -----

-- 
Lubomir Host 'rajo' <rajo AT platon.sk>   ICQ #:  257322664   ,''`.
Platon Group                              http://platon.sk/  : :' :
Homepage: http://rajo.platon.sk/                             `. `'
http://www.gnu.org/philosophy/no-word-attachments.html         `-



Další informace o konferenci linux