MySQL, PHP, Lightswitch a kódování
Předem svého příspěvku bych chtěl předeslat, že nejsem vývojář a mám nulové zkušenosti s PHP.
Mám nepříliš složitou aplikaci, která sestává z DB (MySQL, 7 tabulek) a ze dvou frontendů - jeden jednoduchý v PHP, který slouží pro nahlížení na některá data a pro nejjednodušší insert do jedné tabulky. Druhý pak v MS Lightswitch.
K přístupu k datům používám MySQL Workbench, aplikace běží na MariaDB (5.5.29-MariaDB), PHP ve verzi 5.3.3-7+squeeze14 with Suhosin-Patch.
A teď problém:
Něco mi asi úplně dobře nefunguje v kódování. DB tabulky mám v UTF-8 Czech CI, v HTML backendu mám hlavičku
Kód:
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="cs" lang="cs"><head>
<meta http-equiv="Content-type" content="text/html;charset=utf-8" />
Co nainsertuju přes to PHP, se mi v selectu přes PHP zobrazí v pořádku. V MySQL workbenchi to mám ovšem jakési rozsypané.
Větší problém je to, že jsem do MySQL nalil data z MS SQL a na encoding jsem se tak nějak vykašlal a tom důsledku mám v té Lightswitch aplikaci vše nainsertované přes PHP opět rozsypané, zatímco původní data z MS SQL zase v pořádku.
Takže mám následující dotaz:
* dá se provést konverze kódování v MySQL, pokud to mám tabulce uložené blbě? ideálně selektivně, tj. where id<nnn
Snažil jsem se na to přijít nějak sám, ale nějak se nedaří - asi by to mělo jít pomocí CONVERT(), ale nevim, jak mu předhodit jinou kódovou stránku než tu, kterou má tabulka. Problém je totiž asi v tom, že tabulka je UTF-8, některá data asi Latin2 či CP1250 (??), ale uložená jako UTF8.
Tu lightswitch aplikaci bych asi vůbec neřešil, protože ji chci stejně eliminovat...
Re: MySQL, PHP, Lightswitch a kódování
Jo, kodovani bylo v mysql vzdycky dobry peklo ... (ja si to uzil pri prechodu z phpbb na vb)
Jedna vec je, jaky znakovy stranky pouzivas v konekci (predpokladam, ze vsechny moderni knihovny maj default utf8).
btw. kdyz pouzivas dovetek CI, tak nemluvis o znakovy strance, ale o collation.
Prvni by asi bylo dobry proverit, jak to mas nastaveny ... a bacha, charset se da nastavit snad na vsech urovnich - server, konekce, databaze, tabulka, sloupecek - kazdy muze bejt nastaveny jinak.
Kód:
SHOW VARIABLES LIKE '%character%';
SHOW VARIABLES LIKE '%colla%';
SHOW CREATE TABLE `tabulka`;
Pokud mas vsechno UTF8, tak bych zkusil to uplne nejjednodussi (samozrejme po zaloze te databaze).
Kód:
UPDATE tabulka SET spatne_kodovany_sloupec=_latin2`spatne_kodovany_sloupec` WHERE id < nnn;
popripade mozna i s tim convertem
Kód:
UPDATE tabulka SET spatne_kodovany_sloupec=CONVERT(_latin2`spatne_kodovany_sloupec` USING utf8) WHERE id < nnn;
(popripade cp1250 misto latin2)
Edit: Vsechno spatne, zpatky na stromy;
Kód:
UPDATE tabulka SET spatne_kodovany_sloupec=CONVERT(CAST(`spatne_kodovany_sloupec` AS CHAR CHARACTER SET latin2) USING utf8) WHERE id < nnn;
Edit2: jeste par pokusu a zjistil jsem, ze kdyz se do utf8 sloupce pokusis vlozit nevalidni utf8, tak ho mysql zahodi. tzn. muze se stat, ze tam nektery data vubec mit nebudes.
Kdybys s tim valcil nejak hodne, tak by mozna pomohl vzorek dat - dobrych a spatnych.
2 Příloh-a(y)
Re: MySQL, PHP, Lightswitch a kódování
UFFF, tak to je divočina (teda ty výsledky):
Kód:
character_set_client, utf8character_set_connection, utf8
character_set_database, utf8
character_set_filesystem, binary
character_set_results, utf8
character_set_server, latin1
character_set_system, utf8
character_sets_dir, /usr/share/mysql/charsets/
Kód:
collation_connection, utf8_general_ci
collation_database, utf8_czech_ci
collation_server, latin1_swedish_ci
(názvu tabulky si nevšímej, já vím ;D)
Kód:
CREATE TABLE `Transaction` (
`IDTransaction` int(11) NOT NULL AUTO_INCREMENT,
`TransactionName` varchar(30) COLLATE utf8_czech_ci DEFAULT NULL,
`TransactionDescription` varchar(100) COLLATE utf8_czech_ci DEFAULT NULL,
`DateCreate` datetime NOT NULL,
`Amount` decimal(10,2) NOT NULL,
`Accounted` bit(1) NOT NULL DEFAULT b'0',
`DateAccounted` datetime DEFAULT NULL,
`rAccountID` tinyint(4) NOT NULL,
`rCategoryID` tinyint(4) NOT NULL,
`rClientID` tinyint(4) NOT NULL,
`rUserIDCreate` tinyint(4) NOT NULL,
PRIMARY KEY (`IDTransaction`),
KEY `FK_rAccountID_idx` (`rAccountID`),
KEY `FK_CategoryID_idx` (`rCategoryID`),
KEY `FK_ClientID_idx` (`rClientID`),
KEY `FK_UserIDCreate_idx` (`rUserIDCreate`),
CONSTRAINT `FK_AccountID` FOREIGN KEY (`rAccountID`) REFERENCES `Account` (`IDAccount`) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT `FK_CategoryID` FOREIGN KEY (`rCategoryID`) REFERENCES `Category` (`IDCategory`) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT `FK_ClientID` FOREIGN KEY (`rClientID`) REFERENCES `Client` (`IDClient`) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT `FK_UserIDCreate` FOREIGN KEY (`rUserIDCreate`) REFERENCES `User` (`IDUser`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=7252 DEFAULT CHARSET=utf8 COLLATE=utf8_czech_ci
Jinak ten convert... Nejsem si jist, možná to vypadá, že to zdrojové kódování je úplně jiné.
Dotaz:
Kód:
select
TransName,
CONVERT(CAST(`TransName` AS CHAR CHARACTER SET cp1250) USING utf8),
CONVERT(CAST(`TransName` AS CHAR CHARACTER SET latin2) USING utf8)
from tabulka
má následující výsledky:
Příloha 10041
Příloha 10042
kdy první řádek byl zadaný přes Lightswitch a jeho chování je stejné, jako u chybně importovaných dat, a druhý řádek byl zadaný přes PHP a chová se tak, jak bych chtěl.
Re: MySQL, PHP, Lightswitch a kódování
Kód:
select
hex(TransName),
hex(CONVERT(CAST(`TransName` AS CHAR CHARACTER SET cp1250) USING utf8)),
hex(CONVERT(CAST(`TransName` AS CHAR CHARACTER SET latin2) USING utf8))
from tabulka
Re: MySQL, PHP, Lightswitch a kódování
Tak tady to je ...
Kód:
select TransNum,
TransName,
hex(TransName),
hex(CONVERT(CAST(`TransName` AS CHAR CHARACTER SET cp1250) USING utf8)),
hex(CONVERT(CAST(`TransName` AS CHAR CHARACTER SET latin2) USING utf8))
from vGetTransactions
order by TransNum desc
limit 2
Kód:
'7256', 'ěšÄřžýáÃé', 'C384E280BAC385C2A1C384C28DC385E284A2C385C2BEC383C2BDC383C2A1C383C2ADC383C2A9', 'C384E280BA3F3FC3843F3FE284A23F3F3F3F3F3F3FC2AD3FC2A9', 'C3843F3F3FC384C28D3F3F3F3F3F3F3F3F3FC2AD3F3F''7255', 'ešcržýáíé', '65C5A16372C5BEC3BDC3A1C3ADC3A9', '65C5A16372C5BEC3BDC3A1C3ADC3A9', '65C5A16372C5BEC3BDC3A1C3ADC3A9'
7255 = vloženo přes Lightswitch
7256 = vloženo přes PHP
Re: MySQL, PHP, Lightswitch a kódování
Zatim nejjednodussi zpusob, co jsem narychlo vymyslel.
Kód:
SELECT CAST( CAST( CONVERT( CAST( 0xC384E280BAC385C2A1C384C28DC385E284A2C385C2BEC383C2BDC383C2A1C383C2ADC383C2A9 AS CHAR
CHARACTER SET utf8 ) USING latin1 ) AS CHAR CHARACTER SET BINARY ) AS CHAR CHARACTER SET utf8 );
teoreticky by to teda mohlo jit takhle
Kód:
SELECT CAST( CAST( CONVERT( sloupecek USING latin1 ) AS CHAR CHARACTER SET BINARY ) AS CHAR CHARACTER SET utf8 );
Problem spociva v tom nastaveni serveru na latin1. Lichtsvist si nenastavi charset konekce a dochazi tak ke konverzi utf8 z latin1 do utf8 ...
Reseni jsou dve (a muzes je udelat obe paralelne);
a) do my.cnf
character-set = utf8
b) v lichtsvisti nastavit charset pri pripojovani
b1) primo v driveru
b2) prvni query konekce SET CHARACTER SET utf8;
Re: MySQL, PHP, Lightswitch a kódování
Hmm! Díkes, vypadá to zajímavě, ten druhej dotaz mi při pokusu o update padne:
Kód:
1 row(s) affected, 1 warning(s): 1366 Incorrect string value: '\xCDJEM' for column 'CategoryName' at row 1 Rows matched: 1 Changed: 1 Warnings: 1
Šlo o pokus update hodnoty "PŘÍJEM" s tím, že tam po update zůstalo jen "P?" .
Jdu ještě checknout ten první příklad.
Jinak s tím LS bude asi ještě problém, asi to celý eliminuju... nejde tam nikde nastavit parametry connection k DB, nebo jsem blbej.
edit
tak oba dva dotazy mi při spuštění z workbenche (který mj. zobrazuje data stejně blbě jako LS) skončí se stejným výsledkem.
Jdu si pohrát s nastavením connection z workbenche, ať se to chová jako to PHP.
edit2
tak jsem spustil ten update přímo z PHP a on mi to prostě vždycky ořízne.. kua, jdu koumat dál ;D
Re: MySQL, PHP, Lightswitch a kódování
Mno, tak jsem to po poměrně dlouhé době rozsekl... importuji data z čistého zdroje, kde si můžu zvolit kódování, jak chci, a furt mi to nějak nejde.
Tak se v tom vrtám a vrtám a hle, nenastavoval jsem si v PHP kódování klienta... takže jsem nakrásně mohl mít ve zdrojových datech UTF8, importovat do UTF8, v DB ukládat jako UTF8, ale zobrazoval jsem to jako bůh ví co.
Takže pro příště...
Kód:
$mysqli->set_charset("utf8");