Postgres + PHP = unicodeproblem

Tråden skapades och har fått 13 svar. Det senaste inlägget skrevs .
1

Nu ska vi se om jag lyckas förklara arbetsgången och ifall någon kan ha vettig input på mitt problem...

Jag har ett enkelt PHP-script, encoding är utf-8. Jag kopplar upp mot en databas som mig veterligen inte är Unicode internt, utan snarare sqlascii eller något.

Efter detta sätter jag client encoding till UNICODE, jag har testat de flesta sätt som exvis pg_set_client_encoding samt att göra det via SQL, samt både och.

Jag kör en fråga, hämtar en rad med pg_fetch_assoc, och sparar över den i en vektor. Om jag nu, på valfritt sätt, exvis genom print_r, väljer att skriva ut innehållet i min vektor rakt upp och ner från mitt script, som är utf-8 encodeat, så kommer inte texterna i vektorn att fungera (med åäö exvis), om jag inte utf8_encode()ar varje textsträng för sig. :eek:

Detta är riktigt märkligt, eftersom ifall jag väljer att skriva ut vad som helst som hårdkodas in i scriptet med exvis echo 'åäö' så fungerar det utan problem.

Skriver jag ut pg_get_client_encoding() får jag mkt riktigt 'UNICODE' som resultat... :/

Så - vad f*n ska jag ta mig till?

Behöver jag nämna att jag slitit mitt hår med det här halva dan?

Visst ja - väljer jag i Firefox meny view -> character encoding får jag som sig bör utf-8 som resultat, så skriptets output är verkligen utf-8.

  • Medlem
  • Kiruna
  • 2006-03-14 16:36

Vilken version av PostgreSQL? Vilken libpq-version är PHP-modulen kompilerad mot? Det låter som att du har en gammal version, utan stöd för multibyte-tecken.

Php 5.1.2, postgres 7.4 om jag inte minns fel.

Utdrag:
PostgreSQL(libpq) Version 7.4.7
Multibyte character support enabled
SSL support enabled
Active Persistent Links 0
Active Links 0

  • Medlem
  • Kiruna
  • 2006-03-14 16:57

Det där var bara php-modulen. Hur är det med själva servern? (SHOW ALL är din kompis...)

7.4 är ju i vilket fall som helst inte pinfärsk. Har du möjlighet att uppgradera så rekommenderar jag det.

Detta är vad jag lyckades vaska fram...

Men det ska ju inte spela någon roll vad client encodingen är, eftersom jag ändrar denna innan det aktuella utdraget från databasen....

client_encoding | SQL_ASCII
server_encoding | SQL_ASCII
server_version | 7.4.7
lc_collate | C
lc_ctype | C
lc_messages | en_DK
lc_monetary | en_DK
lc_numeric | en_DK
lc_time | en_DK

  • Medlem
  • Kiruna
  • 2006-03-14 17:15

Fanns det inget om multibyte character support?

Jag har iofs aldrig kört en klient med multibyte-stöd mot en server som inte har det, men jag kan tänka mig att det skulle leda till problem. (Man tycker att klienten skulle kunna översätta själv, men det är inte självklart.) Kolla en gång till om servern har multibyte-stöd; har den inte det skulle jag satsa ända upp till en femtioöring på att det är orsaken till ditt problem.

För att börja nysta i en annan tråd: vad är responsen när du försöker sätta klientkodningen från PHP? (Vad är exempelvis returvärdet från pg_set_client_encoding? Vad svarar servern efter SET client_encoding?)

Multibyte har (väl) inget med unicode-encoding att göra?

Responsen är "0", vilket innebär att den sattes utan problem.

Skriver jag ut aktuell encoding efter att jag satt den, så får jag mkt riktigt att den ska vara UNICODE.

Det är som om PHP tappar greppet om encodingen när datan rent faktiskt hämtas till vektorn, d v s vid pg_fetch_assoc...

  • Medlem
  • Kiruna
  • 2006-03-14 17:50
Citat:

Multibyte har (väl) inget med unicode-encoding att göra?

Eh, joo... Den teckenkodning som PostgreSQL betecknar som UNICODE är egentligen UTF-8, vilken använder från en till fyra bytes per tecken, allt efter behov. För att kunna lagra UTF-8 kodad text måste PostgreSQL < v 8.0 kompileras med multibytestöd. Nu var det inte detta som var ditt problem, eftersom texten var lagrad som SQL_ASCII.

Citat:

Det är som om PHP tappar greppet om encodingen när datan rent faktiskt hämtas till vektorn, d v s vid pg_fetch_assoc...

Detta får mig åter att misstänka att, för att klienten framgångsrikt ska kunna konvertera från SQL_ASCII till UTF-8, så måste även servern vara kompilerad med multibyte-stöd. Jag kan dock inte verifiera det eftersom jag inte har tillgång till en såpass gammal version av PostgreSQL. (Har tyvärr inte tid eller lust att kompilera en heller...)

Givetvis kan det vara en bugg i PHP också, men om du har tillgång till servern via psql borde du kunna verifiera problemet den vägen. Se bara till att psql använder samma libpq som PHP.

  • Medlem
  • Kiruna
  • 2006-03-14 18:05

Hittade följande upplysande stycke i dokumentationen:

Citat:

The SQL_ASCII setting behaves considerably differently from the other settings. When the server character set is SQL_ASCII, the server interprets byte values 0-127 according to the ASCII standard, while byte values 128-255 are taken as uninterpreted characters. No encoding conversion will be done when the setting is SQL_ASCII. Thus, this setting is not so much a declaration that a specific encoding is in use, as a declaration of ignorance about the encoding. In most cases, if you are working with any non-ASCII data, it is unwise to use the SQL_ASCII setting, because PostgreSQL will be unable to help you by converting or validating non-ASCII characters.

vilket borde förklara situationen till fullo.

Gjorde även ett snabbtest i 8.1.3 och samma fenomen uppstår här, så det ser ut som att enda lösningen skulle vara att byta databasens teckenkodning. (Eller att låta PHP koda om, som du redan prövat...)

Verkar som om du funnit kärnan till problemet där!

Är det möjligt att ändra teckenkodningen utan att reinitialisera databasen?

  • Medlem
  • Kiruna
  • 2006-03-15 11:37

Man behöver inte köra initdb om det är det du menar, däremot behöver man dumpa -> konvertera dump till rätt teckenkodning -> skapa ny databas med rätt teckenkodning -> importera konverterad dump. Har du BLOBar eller bytea-fält måste du även hantera dem.

För konvertera-steget ovan brukar folk rekommendera iconv.

(Jag tycker mig minnas nån på mailinglistan som helt enkelt uppdaterade pg_database, men då var datan ren ASCII, alltså inga å,ä,ö eller liknande. Möjligen skulle man kunna använda CREATE DATABASE med TEMPLATE parametern, men det kan nog gå åt skogen det med. )

Initdb var vad jag tänkte på. Ska ta och köra ett testrun på det och se om det kan låta sig fixas utan problem - 95% av systemet är ju kodat i iso-8859-1, och jag måste säkerställa mig om att genom att sätta set_client_encoding i includefilen jag använder för att koppla upp mot pg så kommer all input från gamla script fortfarande fungera...

Vilken encoding är rekommenderad att använda för den nya databasen?

  • Medlem
  • Kiruna
  • 2006-03-15 12:22

Den frågan kan du nog svara bäst själv på genom att svara på frågan: vad för data ska lagras?

De två naturliga alternativen är väl i detta fallet LATIN1 (iso-8859-1) om det rör sig om västeuropeiska skriftspråk och UTF8 (UNICODE är du nog tvungen att skriva eftersom du har en äldre PG-version) om du vill kunna hantera ex. kinesiska, arabiska eller liknande. Givetvis funkar UNICODE bra även för västeuropeiska språk, och det kan ju vara bra att ligga steget före om kraven nån gång skulle ändras. Prestandan för de respektive kodningarna får du testa själv med riktiga data, men om det inte rör sig om extremt hög belastning skulle jag inte tro att du märker nån skillnad. (Och då kan du nog ändå vinna betydligt mer på att uppgradera till version 8.1, som innehåller många förbättringar jämfört med 7.4)

1
Bevaka tråden