Check alle échte Black Friday-deals Ook zo moe van nepaanbiedingen? Wij laten alleen échte deals zien

[PHP / Java / MySQL] Cyrillic schrift met UTF8 geeft fouten

Pagina: 1
Acties:

  • Matis
  • Registratie: Januari 2007
  • Laatst online: 20:57

Matis

Rubber Rocket

Topicstarter
Beste PRGers,

Ik weet dat ik me in het hol van de leeuw ga begeven, met betrekking tot encoding, maar ik heb naar eer en geweten overal utf8 / utf8_unicode_ci gebruikt waar mogelijk.
Lang verhaal kort:

Ik heb een website (CodeIgniter2 met daarin Doctrine2 als ORM) en een Java-tooltje, welke beide gebruik maken van dezelfde table in een MySQL-database.

Zowel het Java-tooltje als de PHP-website schrijven in een tabel voor logging.

De database en tabel zien er zo uit:
MySQL:
1
2
3
4
5
6
7
8
9
10
11
CREATE DATABASE `ci_checklists` /*!40100 DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci */$$
CREATE TABLE `release_checks` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `release_id` int(11) NOT NULL,
  `state_id` int(11) NOT NULL,
  `check_id` int(11) NOT NULL,
  `created` datetime NOT NULL,
  `modified` datetime NOT NULL,
  `description` longtext COLLATE utf8_unicode_ci,
  PRIMARY KEY (`id`),
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci$$


Ik wilde als test zowel uit de Java-tool als vanaf de PHP-website een hele zwik non-ascii karakters naar de database sturen:
Afbeeldingslocatie: http://tweakers.net/ext/f/teNAQKdJSbkChl6zgj2IXEF8/thumb.png
Verplicht plaatje, omdat GoT loopt te kloten met het Cyrillisch schrift.

Dit ziet er in de database zo uit:
Afbeeldingslocatie: http://tweakers.net/ext/f/zjSLdwMDWW4uhPFm5CVFzHdt/thumb.png
De bovenste regel is de PHP-regel en de onderste regel is de Java-regel.

Wanneer ik de beide regels weer teruglees in mijn PHP-website, wordt de eerste (PHP)regel goed geschreven op het scherm, maar de tweede (Java)regel niet.

In de Java-tool verbind ik op onderstaande manier met de database:
Java:
1
String dbUrl = "jdbc:mysql://" + _server + ":" + _port + "/" + _schema + "?characterEncoding=UTF-8";

en voor de PHP-website ziet mijn CodeIgniter / Doctrine configuratie er zo uit:
PHP:
1
2
$db['default']['char_set'] = 'utf8';
$db['default']['dbcollat'] = 'utf8_unicode_ci';

In de header van mijn website staat de volgende encoding:
HTML:
1
<meta content="text/html; charset=utf-8" http-equiv="content-type">

De doctype is html.

Het probleem lijkt niet in de browser te zitten, immers geven zowel Chrome, Firefox en IE (de eerste twee zowel op Windows als Ubuntu) het op dezelfde manier weer.

Wanneer ik met de PHP-debugger de twee log-regels bekijk, zie ik inderdaad dat er in het PHP-regel de string wel netjes in het geheugen staat en in het Java-regel staan er het volgende
Afbeeldingslocatie: http://tweakers.net/ext/f/YK0xZSyPLoUOQqOx6oDN3nAW/thumb.png
De eerste 128 karakters zijn die ruitjes met vraagtekens, de vraagtekens representeren het Cyrillisch schrift. De leestekens tussen de Cyrillische karakters, worden wel goed weergegeven.
Zoals de regels in het geheugen staan, worden ze ook in de browser weergegeven. Het probleem lijkt dus niet in de vertaalslag tussen PHP en de browser te zitten.

Wie-o-wie kan me helpen dit encoding-probleem te tackelen?

Thnx :)

Matis

Edit; Misschien ook nog wel een leuk detail: Wanneer ik een var_dump doe van beide regels, dan krijg ik in het geval van de foute Java-regel een lengte van 470 karakters terug en in het geval van de goede PHP-regel een lengte van 800 karakters.
De lengte van de originele string bedraagt 470 karakters.

Edit 2; Ik heb zojuist een testje gedraaid waarin binnen de Java-tool de twee strings terug worden gelezen (al zal dit in het echt nooit gebeuren, want de website is de logging frontend), maar daarin wordt door Java de string zo weergegeven als dat ie in de database zit. In het geval van de Java-string is dat exact als wat ik er in zat, in het geval van de PHP-string, is dat zoals het database-screenshot het laat zien.
Afbeeldingslocatie: http://tweakers.net/ext/f/ScPCZ3K2WDQmuYsP3zNUotM3/thumb.png

[ Voor 12% gewijzigd door Matis op 14-11-2012 14:59 ]

If money talks then I'm a mime
If time is money then I'm out of time


  • Hydra
  • Registratie: September 2000
  • Laatst online: 06-10 13:59
Euh, maar de lengte in Java is goed en de Java regel komt goed in de DB terecht toch? De bovenste (PHP) regel in je database lijkt in dat screenshot fout te zijn, of vergis ik me nu?

https://niels.nu


  • Matis
  • Registratie: Januari 2007
  • Laatst online: 20:57

Matis

Rubber Rocket

Topicstarter
Hydra schreef op woensdag 14 november 2012 @ 15:23:
Euh, maar de lengte in Java is goed en de Java regel komt goed in de DB terecht toch?
Correct, de Java-regel komt goed in de DB terecht, maar wordt verkeerd door PHP-ingelezen.
De bovenste (PHP) regel in je database lijkt in dat screenshot fout te zijn, of vergis ik me nu?
De PHP-regel komt inderdaad verkeerd in de database terecht, maar wordt weer goed teruggelezen in de website.

Je zou het ongeveer zo kunnen samenvatten:
Java => database (goed) => Java (goed)
Java => database (goed) => PHP (fout)
PHP => database (fout) => Java (fout, letterlijk zoals de regel in de DB staat).
PHP => database (fout) => PHP (goed)

If money talks then I'm a mime
If time is money then I'm out of time


  • Hydra
  • Registratie: September 2000
  • Laatst online: 06-10 13:59
PHP doet het dus fout. Het is een bekend issue dat PHP issues heeft met utf. De standaard string functies kunnen met niet UTF omgaan.

http://tympanus.net/codro...g-php-mysql-utf-8-issues/ zou de oplossing kunnen bieden.

[ Voor 22% gewijzigd door Hydra op 14-11-2012 15:58 ]

https://niels.nu


  • Cartman!
  • Registratie: April 2000
  • Niet online
De rest is net zo belangrijk maar het laatste puntje gaat je probleem oplossen, na het connecten een query uitvoeren:

code:
1
SET NAMES 'utf8'


Dat het nu niet werkt is "normaal" zal ik maar zeggen.

  • Matis
  • Registratie: Januari 2007
  • Laatst online: 20:57

Matis

Rubber Rocket

Topicstarter
Hydra schreef op woensdag 14 november 2012 @ 15:57:
PHP doet het dus fout. Het is een bekend issue dat PHP issues heeft met utf. De standaard string functies kunnen met niet UTF omgaan.

http://tympanus.net/codro...g-php-mysql-utf-8-issues/ zou de oplossing kunnen bieden.
Thnx voor de tip, onvoorstelbaar dat PHP niet overweg kan met utf-8 |:(
Cartman! schreef op woensdag 14 november 2012 @ 16:02:
De rest is net zo belangrijk maar het laatste puntje gaat je probleem oplossen, na het connecten een query uitvoeren:

code:
1
SET NAMES 'utf8'


Dat het nu niet werkt is "normaal" zal ik maar zeggen.
Ik moet eerlijkheidshalve bekennen dat ik dat SET NAMES al een keertje voorbij heb zien komen in mijn zoektocht naar de problematiek.
Ik heb (zoals ze adviseren op het doctrine2 forum) de volgende configuratie gemaakt voor doctrine
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
$connection_options = array(
            'driver'        => 'pdo_mysql',
            'user'          => $db['default']['username'],
            'password'      => $db['default']['password'],
            'host'          => $db['default']['hostname'],
            'dbname'        => $db['default']['database'],
            'charset'       => $db['default']['char_set'],
            'driverOptions' => array(
                'charset'   => $db['default']['char_set'],
                PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'utf8'",
            ),
        );

Dat zou, na het initialiseren van de PDO (1002) het "SET NAMES 'utf8'" commando uit moeten voeren, maar dat zie ik helaas nog niet voorbijkomen.

Edit; Now breaks my wooden shoe! Het "SET NAMES 'utf8'" wordt wel degelijk uitgevoerd tijdens het initialiseren van Doctrine/PDO, maar niet via de reguliere paden binnen Doctrine.
Resume, de door Java-geinserte logregels worden nu wel goed weergegeven in de website *O*. De (voorheen) geschreven regels door PHP worden nu verkeerd weergegeven op de website *O* .
Het lijkt dus wel opgelost nu.

De strlen van de goede utf-8 string blijft overigens wel 800 teruggeven, maar dat zal waarschijnlijk het aantal bytes zijn en niet de hoeveelheid karakters ofzo. Het zal vast wel gedocumenteerd staan dat het fubar werkt :P

Edit2; Wanneer de volgende functie wordt gebruikt, wordt de SET NAMES wel via de reguliere paden van Doctrine uitgevoerd:
PHP:
1
$this->em->getConnection()->setCharset('utf8');


De uitkomst is overigens hetzelfde :D

[ Voor 21% gewijzigd door Matis op 14-11-2012 17:46 ]

If money talks then I'm a mime
If time is money then I'm out of time


  • Cartman!
  • Registratie: April 2000
  • Niet online
Matis schreef op woensdag 14 november 2012 @ 17:37:
[...]
Thnx voor de tip, onvoorstelbaar dat PHP niet overweg kan met utf-8 |:(
Opzich kan PHP prima overweg met utf-8, je moet alleen een paar dingen goed instellen.

  • Matis
  • Registratie: Januari 2007
  • Laatst online: 20:57

Matis

Rubber Rocket

Topicstarter
Cartman! schreef op woensdag 14 november 2012 @ 17:46:
Opzich kan PHP prima overweg met utf-8, je moet alleen een paar dingen goed instellen.
Dat is inderdaad gebleken :) Het lijkt allemaal normaal te werken, tenzij je de string-functies er op los laat (zoals Hydra al aangaf).
The easiest way to determine the character count of a UTF8 string is to pass the text through utf8_decode() first:
PHP:
1
2
3
<?php
$length = strlen(utf8_decode($s));
?>

utf8_decode() converts characters that are not in ISO-8859-1 to '?', which, for the purpose of counting, is quite alright.
:Y)

[ Voor 5% gewijzigd door Matis op 14-11-2012 17:51 ]

If money talks then I'm a mime
If time is money then I'm out of time


  • Cartman!
  • Registratie: April 2000
  • Niet online
Je hebt de link niet goed doorgelezen, je kunt beter gebruik maken van mb_strlen() ;)

  • Gomez12
  • Registratie: Maart 2001
  • Laatst online: 17-10-2023
Cartman! schreef op woensdag 14 november 2012 @ 18:39:
Je hebt de link niet goed doorgelezen, je kunt beter gebruik maken van mb_strlen() ;)
Compleet andere functie gebruiken noem jij "anders instellen"?

  • Cartman!
  • Registratie: April 2000
  • Niet online
Ik begrijp je punt maar als je altijd alles als utf8 behandelt dan is het gebruik van de mb_* stringfuncties al snel normaal.

Instellen is dus de goede header plaatsen + de juiste query uitvoeren om de juiste encoding terug te krijgen (waarbij de laatste meer een MySQL-ding is dan PHP-ding). Daarna dus het gebruiken van de juiste functies.

  • Hydra
  • Registratie: September 2000
  • Laatst online: 06-10 13:59
Je moet gewoon eigenlijk standaard van de UTF-ready functies gebruik maken. Dat is veel minder werk dan er later achterkomen dat een klant waarvoor je werkt "rare tekens" gebruikt en je de hele bende moet omzetten.

https://niels.nu


  • Matis
  • Registratie: Januari 2007
  • Laatst online: 20:57

Matis

Rubber Rocket

Topicstarter
Cartman! schreef op woensdag 14 november 2012 @ 18:39:
Je hebt de link niet goed doorgelezen, je kunt beter gebruik maken van mb_strlen() ;)
Dat heb ik wel, maar var_dump maakt gebruik van strlen om de lengte van een string (ongeacht de encoding) te bepalen. Derhalve ging ik op zoek naar een waarschuwing op php.net, naar de gevaren van strlen op een UTF8-string, maar die kon ik niet vinden. Anders dan in de comments van de gebruikers.

Daarnaast ben ik het wel met Hydra eens, dat het een goed gebruik is om de mb-functies te gaan gebruiken in de toekomst :)

[ Voor 11% gewijzigd door Matis op 14-11-2012 22:45 ]

If money talks then I'm a mime
If time is money then I'm out of time


  • Gomez12
  • Registratie: Maart 2001
  • Laatst online: 17-10-2023
Hydra schreef op woensdag 14 november 2012 @ 20:03:
Je moet gewoon eigenlijk standaard van de UTF-ready functies gebruik maken. Dat is veel minder werk dan er later achterkomen dat een klant waarvoor je werkt "rare tekens" gebruikt en je de hele bende moet omzetten.
Simplistische vraag van mijn kant dan : Zijn alle stringfuncties dan al beschikbaar in mb_ varianten? Of enkel het meerendeel en sommige nog niet?

Laatste keer dat ik keek namelijk staat me iets bij dat niet alle functies beschikbaar waren of dat er enkele andere functies waren die intern nog niet mb_compatible waren, waardoor het voor mij neerkwam op : mb_ functies gebruiken is meer een bug-veroorzakend iets dan een bug-oplossend iets (ik heb tenminste geen zin om alles in mb_functies uit te drukken en er later achter te komen dat functie x/y/z nog niet 100% bruikbaar is, dan maar liever zekerheid en zeggen dat volledig utf-8 niet ondersteund wordt)

  • Hydra
  • Registratie: September 2000
  • Laatst online: 06-10 13:59
Ik doe al eeuwen niks meer met PHP dus dat antwoord moet ik je schuldig blijven.

https://niels.nu

Pagina: 1