[PHP] character encoding ingelezen RSS feed

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • dvdheiden
  • Registratie: Maart 2006
  • Laatst online: 20:20
Aangezien ik graag het voetbalnieuws volg, maar niet elke keer alle voetbalsites wil bezoeken heb ik in PHP d.m.v. SimpleXML een scriptje gemaakt die de RSS feeds van een aantal sites inleest en dat nieuws verzameld.

Om het "gebruikelijke" charset probleem te ontlopen heb ik mezelf aangeleerd om altijd alles in UTF8 te doen, hiervoor doorloop ik de volgende stappen (voor de volledigheid het geheel, maar het gaat al bij stap 1 mis):

De data uit de rss gaat uiteindelijk door de volgende check:
PHP:
1
2
if (mb_detect_encoding($s, "UTF-8", true) != "UTF-8")
        $s = utf8_encode($s);


In de database staan alle velden op utf8_unicode_ci.

De uiteindelijke pagina voorzie ik van UTF8 door zowel de header mee te sturen:
PHP:
1
header("Content-type: text/html; charset=utf-8");

...als in de meta-tags:
HTML:
1
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />


De pagina geeft dan ook netjes de juiste "Tekenset", te weten utf8.

Nu gaat het echter al mis bij het plaatsen van de data in de database, de gebruikelijke "vreemde" tekens verschijnen al, dingen als: â€. Daarom ben ik gaan kijken wat bovenstaande check in php oplevert, maar die geeft keurig elke keer UTF-8 terug, dus:
code:
1
echo 'mb_detect_encoding($s, "UTF-8", true):' . mb_detect_encoding($s, "UTF-8", true);

geeft:
code:
1
mb_detect_encoding($s, "UTF-8", true): UTF-8


Een voorbeeld van de bron waar het mis gaat is deze. De browser geeft als "Tekenset" UTF-8 maar in de xml staat:
XML:
1
<?xml version="1.0" encoding="ISO-8859-1" ?>


Kortom, het lijkt alsof die data niet UTF8 is, maar waarom vertelt mb_detect_encoding mij dan van wel?

Inmiddels ben ik zo week in de paasei geworden van dit probleem 8)7 |:( :F , dat ik even een zetje in de goede richting nodig heb. Wie heeft de gouden tip?

Acties:
  • 0 Henk 'm!

  • matthijsln
  • Registratie: Augustus 2002
  • Laatst online: 11-09 14:07
De link die je geeft is in UTF-8 (zie "Piqué/Piqué), zoals ook in de Content-Type HTTP response header staat, die boven de character set gaat die in een meta http-equiv of xml declaratie staat: http://www.w3.org/Interna...g-declarations#precedence

Waarom volg je niet gewoon de HTTP standaard? De Content-Type header is er niet voor niets. Het detecteren van een encoding blijft natuurlijk gissen.

Acties:
  • 0 Henk 'm!

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 23:10

Janoz

Moderator Devschuur®

!litemod

Je hele keten zit netjes in elkaar, je probleem zit (zoals je zelf ook al aangaf) bij de poort. mb_detect_encoding is eigenlijk een heel smerige manier. Je kunt beter gewoon kijken wat je bron zelf zegt dat de encoding is. Dat wordt naast in de xml tag, ook vast wel in de headers gezet.

Helaas kun je daar ook niet altijd vanuit gaan trouwens aangezien vele ontwikkelaars op 1 of andere manier erg veel moeite hebben met zo iets simpels ;) als encoding. In dat geval zit er eigenlijk weinig anders op om per bron een uitzondering ergens in te programeren (dus dat je bijvoorbeeld naast de feedURL ook een encoding op kunt geven wanneer deze afwijkt)

Het posten van Joels linkje laat ik vandaag aan iemand anders over aangezien je je eigen spulleboel wel op orde hebt.

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Acties:
  • 0 Henk 'm!

  • dvdheiden
  • Registratie: Maart 2006
  • Laatst online: 20:20
Bedankt voor de reacties!

Als ik dus kijk naar de bron, geeft deze als tekenset dus utf8, maar staat dus in de xml de encoding ISO-8859-1.

Als ik dus de HTTP standaard volg (de link van matthijsln), wordt de encoding van de xml pas als derde meegenomen in de bepaling, en wordt er dus eerst gekeken naar de HTTP Content-Type header wat dus ook utf8 oplevert. Dan zou ik de data dus niet hoeven te converteren voordat het in de database gaat. Dat is echter al wat er nu gebeurt. Maar toch levert dat de "vreemde" tekens op (wat ik dan niet verwacht).

Kortom, ik begrijp het wel, maar snappen doe ik het nog niet (Bassie (TM))

[ Voor 2% gewijzigd door dvdheiden op 07-04-2011 10:46 . Reden: tiepsfouts ]


Acties:
  • 0 Henk 'm!

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 23:10

Janoz

Moderator Devschuur®

!litemod

Dat je het niet begrijpt is eigenlijk redelijk simpel te verklaren. Jij doet de aanname dat de rest van de wereld alles op orde heeft. Maar je hebt hier gewoon te maken met een bron van (encodingwise) pruts kwaliteit.

Ik denk dat je hier eerst even de daadwerkelijk gebruikte encoding moet proberen uit te vinden en vervolgens een uitzondering in je eigen code moet maken om hun prutswerk weer even recht te trekken.

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Acties:
  • 0 Henk 'm!

  • dvdheiden
  • Registratie: Maart 2006
  • Laatst online: 20:20
Duidelijk verhaal, ik ga eens even kijken hoe ik dat op een nette wijze voor elkaar kan krijgen. Ben bang dat ik naar je eerder genoemde oplossing zal moeten gaan (het opslaan van de charset bij de feedUrl) al vind ik dat ergens natuurlijk wel een minder mooie oplossing.

Acties:
  • 0 Henk 'm!

  • fleppuhstein
  • Registratie: Januari 2002
  • Laatst online: 07-09 13:37
HackZois schreef op donderdag 07 april 2011 @ 11:05:
Duidelijk verhaal, ik ga eens even kijken hoe ik dat op een nette wijze voor elkaar kan krijgen. Ben bang dat ik naar je eerder genoemde oplossing zal moeten gaan (het opslaan van de charset bij de feedUrl) al vind ik dat ergens natuurlijk wel een minder mooie oplossing.
De schoonheid van de oplossing zit hem in de methode waarop jij het implementeert. Een encoding is een redelijk statisch, en zal niet met elk request wijzigen. Als jij tijdens het toevoegen (al dan niet via een backoffice interface) mee geeft dat de encoding iets anders is dan wat er wordt mee gegeven, of desnoods weergeeft wat welke encoding voor effect heeft zodat je direct ziet wat het effect van de gekozen encoding is,

Moraal is: Uitzonderingen zijn er altijd (de kans hierop neemt toe bij connecties met derden), het gaat erom hoe jij het oplost. Hard coded vs Dynamisch, Veronderstellingen vs Testen

[ Voor 10% gewijzigd door fleppuhstein op 07-04-2011 11:14 ]


Acties:
  • 0 Henk 'm!

  • matthijsln
  • Registratie: Augustus 2002
  • Laatst online: 11-09 14:07
Janoz schreef op donderdag 07 april 2011 @ 10:59:
Dat je het niet begrijpt is eigenlijk redelijk simpel te verklaren. Jij doet de aanname dat de rest van de wereld alles op orde heeft. Maar je hebt hier gewoon te maken met een bron van (encodingwise) pruts kwaliteit.
De gegeven bron is van prima kwaliteit volgens de geldende standaarden. In de Content-Type response header van http://www.vi.nl/ADO-Den-Haag-1/ADO-Den-Haag.htm staat namelijk "text/xml;charset=utf-8". De response body is ook in UTF-8. Dat in de XML declaratie ISO-8859-1 staat moet worden genegeerd volgens de al eerder gelinkte precedence regels (ok, netjes is het niet).

Acties:
  • 0 Henk 'm!

  • dvdheiden
  • Registratie: Maart 2006
  • Laatst online: 20:20
De bron is inderdaad UTF-8. Overigens heeft de oplosing van Janoz al voor één bron het probleem opgelost, maar nog niet voor het eerder gegeven voorbeeld.

Dan gaat er toch nog iets anders mis, immers komt de data niet goed in de database terecht. De data is dus UTF-8, de database is UTF-8:
SQL:
1
SHOW VARIABLES LIKE 'character%'

levert:
code:
1
2
3
character_set_client    utf8
character_set_connection    utf8
character_set_database  utf8

Ook geprobeerd om bij de verbinding het goed op te geven:
SQL:
1
SET NAMES utf8

Dus dat staat volgens mij goed.

Volgens mij zit het probleem dus al eerder. De data lees ik in met curl en gaat vervolgens gelijk naar simpleXML d.m.v. simplexml_load_string. Vervolgens doorloop ik de xml channel items, daar zitten enkele bewerkingen op (o.a. op de datum en url) en die mik ik in een array:
PHP:
1
2
3
4
5
6
7
8
9
$xml = simplexml_load_string($source);
$articles = array();
$items = $xml->channel->item;
foreach ($items as $item) {
    $article = array();
    $article['title'] = $item->title;
    ...snip...
    $articles[] = $article;
}


En dat daar worden eenvoudige query's van gemaakt die naar de database worden weggeschreven. Ik heb dus echt geen idee waar ergens het fout zou kunnen gaan.

Acties:
  • 0 Henk 'm!

  • YopY
  • Registratie: September 2003
  • Laatst online: 13-07 01:14
Ik kan evt. wel aan de menschen aldaar doorgeven dat hun encoding niet helemaal deugt, :+). Voor enkele zustersites van die site (zoals vn.nl etc, zelfde moederbedrijf) heb ik ook lang met systeembeheer moeten communiceren voordat de content headers en encoding enzo goed zat (en daaruitvolgend de RSS feed(s) correct op andere sites verscheen).

Acties:
  • 0 Henk 'm!

  • Precision
  • Registratie: November 2006
  • Laatst online: 12-08 21:08
YopY schreef op donderdag 07 april 2011 @ 21:20:
Ik kan evt. wel aan de menschen aldaar doorgeven dat hun encoding niet helemaal deugt, :+). Voor enkele zustersites van die site (zoals vn.nl etc, zelfde moederbedrijf) heb ik ook lang met systeembeheer moeten communiceren voordat de content headers en encoding enzo goed zat (en daaruitvolgend de RSS feed(s) correct op andere sites verscheen).
Ik pas soms gewoon scraping toe van een website, ik voeg wel netjes een extra header toe waarop je mij kunt contacteren. Want laatst ging het fout op een xml bestandje van +150 000 items, het was gewoon sneller om doormiddel van scraping de juiste content op te halen. Dan zijn systeembeheerders (/programmeurs) ook weer niet happy, maar ik ben dan weer niet happy als zij hun werk niet (goed) doen. Ahja ik heb meerdere ip-adressen en verander m'n headers en zo goed als alles waarop je kunt blokken dus. Het gaat bij mij meestal om een éénmalige import, wat eigenlijk jou probleem niet oplost.

Crisis? Koop slim op Dagoffer - Op zoek naar een tof cadeau?


Acties:
  • 0 Henk 'm!

  • dvdheiden
  • Registratie: Maart 2006
  • Laatst online: 20:20
Inmiddels de encoding meegenomen zoals Janoz voorstelde en dan met iconv omgezet als het geen UTF8 is.
Pagina: 1