[PHP] Special characters in de buffer van CSV schrijf script

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • bindsa
  • Registratie: Juli 2009
  • Niet online
Ik heb een script gemaakt dat data uit een MySQL tabel haalt en deze als .csv aan de client aanbied. Werkt allemaal perfect, alleen gaat het mis als er speciale characters in de $csv variabele komen. Ik heb van alles geprobeerd met charsets enzo maar het lukt maar niet. Als ik eerst de info wegschrijf naar een .csv op de server en die als download aanbiedt, werkt het wel prima. Maar dat wil ik niet, ik wil het direct aan bieden. Het script:


PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
    $csv = "";
    $userdata = dbquery("SELECT * FROM userdata");
    while($array = mysql_fetch_array($userdata, MYSQL_NUM)) {
        $csvstring = '"' . implode('";"', $array) . '"';
        $csvstring = html_entity_decode($csvstring, ENT_NOQUOTES);
        $csv .= $csvstring;
        $csv .= "\n";
    }
    $filesize = mb_strlen($csv, '8bit');
    $filename = "csvtest.csv";
    header('Content-Description: File Transfer');
    header('Content-Type: text/csv');
    header("Content-Disposition: attachment; filename=\"".$filename."\";");
    header('Content-Transfer-Encoding: binary');
    header('Content-Length: ' . $filesize);
    header('Expires: 0');
    header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
    header('Pragma: public');
    ob_clean();
    flush();
    echo "$csv";
    exit;


En dit werkt wel om de een of andere vage reden:

PHP:
1
2
3
4
5
6
7
8
9
10
11
    $csv = "";
    $userdata = dbquery("SELECT * FROM userdata");
    $handle = fopen("testfile2.csv", "w") or die("Can't open file");
    while($array = mysql_fetch_array($userdata, MYSQL_NUM)) {
        $csvstring = '"' . implode('";"', $array) . '"';
        $csvstring = html_entity_decode($csvstring, ENT_NOQUOTES);
        $csv .= $csvstring;
        $csv .= "\n";
    }
    fwrite($handle, $csv);
    fclose($handle) or die("Could not close file");


Zo zou het moeten:
code:
1
"René";"Van De";"Biezen";

En zo krijg ik het:
code:
1
"Ren;";"Van De";"Biezen";

(In werkelijkheid staat er nu na Ren zo'n mooi vierkant blokje, maar die kan ik hier niet typen)

Ik heb dus geprobeerd om deze regel:
PHP:
1
    header('Content-Type: text/csv');

Te veranderen in:
PHP:
1
    header('Content-Type: text/csv; charset=ISO-8859-1');


Geen resultaat. Wat mis ik?? :?

[ Voor 10% gewijzigd door bindsa op 16-04-2010 17:11 ]


Acties:
  • 0 Henk 'm!

  • Osiris
  • Registratie: Januari 2000
  • Niet online
Wat versta je onder "speciale characters"? En wat heb je geprobeerd qua charsets?

Ah, een edit.

Hoe staat het letterlijk in je DB?

Ah weer een edit, het ging dus niet om een HTML-entity :+

Moet je ff uitvogelen wat voor binaire waarde die character heeft (bestand opslaan en openen in een hex-editor ofzo) en wat de correcte bijbehorende charset is.

[ Voor 72% gewijzigd door Osiris op 16-04-2010 17:13 ]


Acties:
  • 0 Henk 'm!

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
Even uit de blote bol een gokje:
PHP:
1
header('Content-Type: text/csv; charset=xxx');

Expliciet een de juiste charset opgeven.
L0calh0st schreef op vrijdag 16 april 2010 @ 17:06:
(In werkelijkheid staat er nu na Ren zo'n mooi vierkant blokje, maar die kan ik hier niet typen)
Daar hebben ze knippen/plakken voor uitgevonden ;)

[ Voor 52% gewijzigd door RobIII op 16-04-2010 17:11 ]

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


Acties:
  • 0 Henk 'm!

  • bindsa
  • Registratie: Juli 2009
  • Niet online
RobIII schreef op vrijdag 16 april 2010 @ 17:10:
Even uit de blote bol een gokje:
PHP:
1
header('Content-Type: text/csv; charset=xxx');

Expliciet een de juiste charset opgeven.

[...]

Daar hebben ze knippen/plakken voor uitgevonden ;)
Heb ik geprobeerd doet helaas niks. En dat knippen en plakken: Dan converteert het tweakers bericht post script het naar de html entity, dus werkt niet :P

Acties:
  • 0 Henk 'm!

  • bindsa
  • Registratie: Juli 2009
  • Niet online
Osiris schreef op vrijdag 16 april 2010 @ 17:09:
Wat versta je onder "speciale characters"? En wat heb je geprobeerd qua charsets?

Ah, een edit.

Hoe staat het letterlijk in je DB?

Ah weer een edit, het ging dus niet om een HTML-entity :+

Moet je ff uitvogelen wat voor binaire waarde die character heeft (bestand opslaan en openen in een hex-editor ofzo) en wat de correcte bijbehorende charset is.
In de DB staan wel html entities, maar voordat ik het bestand schrijf verander ik die in hun 'normale' waarden met html_entity_decode();

Acties:
  • 0 Henk 'm!

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
L0calh0st schreef op vrijdag 16 april 2010 @ 17:12:
[...]


Heb ik geprobeerd doet helaas niks.
En je weet zeker dat je de juiste charset gespecificeerd hebt of heb je er maar een gegokt ofzo?

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


Acties:
  • 0 Henk 'm!

  • CodeCaster
  • Registratie: Juni 2003
  • Niet online

CodeCaster

Can I get uhm...

Dit komt gewoon hierop neer: The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!).
L0calh0st schreef op vrijdag 16 april 2010 @ 17:12:
Heb ik geprobeerd doet helaas niks.
Het doet wel wat, het geeft aan in welke karakterset de client de ontvangen data moet weergeven. Zorg gewoon dat de karaktersets overal hetzelfde zijn, van database tot php tot html tot http-headers. Als er op één plek een verkeerde karakterset staat gedefinieerd krijg je dit resultaat.

https://oneerlijkewoz.nl
Op papier is hij aan het tekenen, maar in de praktijk...


Acties:
  • 0 Henk 'm!

  • bindsa
  • Registratie: Juli 2009
  • Niet online
CodeCaster schreef op vrijdag 16 april 2010 @ 17:17:
Dit komt gewoon hierop neer: The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!).


[...]

Het doet wel wat, het geeft aan in welke karakterset de client de ontvangen data moet weergeven. Zorg gewoon dat de karaktersets overal hetzelfde zijn, van database tot php tot html tot http-headers. Als er op één plek een verkeerde karakterset staat gedefinieerd krijg je dit resultaat.
Ok dat zal ik ff lezen. Kan ff duren voor ik weer reageer ivm drukte. Maar een reactie gaat zeker komen. In ieder geval bedankt.

Acties:
  • 0 Henk 'm!

  • bindsa
  • Registratie: Juli 2009
  • Niet online
Ok, het artikel heb ik gelezen, daaruit blijkt dat de volgende 2 charsets in mijn situatie zouden moeten werken:
- UTF-8
- ISO-8859-1
Dus dat heb ik geprobeerd, in de HEAD van het document:
HTML:
1
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />

In de PHP header code:
PHP:
1
header('Content-Type: text/csv; charset=UTF-8');


Maar nog niet het gewenste resultaat, nog steeds hetzelfde probleem. De situatie is dus als volgt:
- In de database staan de HTML entities
- Die haal ik eruit in PHP met html_entity_decode(), dat werkt
- Ik weet zeker dat het van de database tot PHP goed gaat, want als ik naar een losse file schrijf is er geen probleem
- Blijft dus over de schakeling van PHP naar de HTTP headers. Deze heb ik (mijns inziens) de juist charset meegegeven in de headers + de HEAD, maar nog steeds werkt het niet.
- Tot slot heb ik geprobeerd om de entities te laten staan, maar dan krijg ik ook entities en de CSV en da's niet wenselijk

Wat zie ik over het hoofd?

Acties:
  • 0 Henk 'm!

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
L0calh0st schreef op vrijdag 16 april 2010 @ 21:42:
Ok, het artikel heb ik gelezen, daaruit blijkt dat de volgende 2 charsets in mijn situatie zouden moeten werken:
- UTF-8
- ISO-8859-1
Dus dat heb ik geprobeerd, in de HEAD van het document:
HTML:
1
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />

In de PHP header code:
PHP:
1
header('Content-Type: text/csv; charset=UTF-8');


Maar nog niet het gewenste resultaat, nog steeds hetzelfde probleem.
Ja, d'uh. Als er ISO-8859-15 in de DB zit en je stuurt dan een andere charset in de http-headers dan gaat dat niet automagisch goed hoor ;)

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


Acties:
  • 0 Henk 'm!

  • storeman
  • Registratie: April 2004
  • Laatst online: 18:38
Aangezien je met htmlentities omzet, weet je zeker dat de uitvoer UTF-8 is? Probeer eens er een utf8_encode() overheen te gooien.

Je zou ook eens kunnen kijken naar de mb_string functies in PHP. Ik had een soortgelijk probleem doordat ik met strtolower ed ging werken, welke niet multibyte zijn.

"Chaos kan niet uit de hand lopen"


Acties:
  • 0 Henk 'm!

  • bindsa
  • Registratie: Juli 2009
  • Niet online
storeman schreef op vrijdag 16 april 2010 @ 21:46:
Aangezien je met htmlentities omzet, weet je zeker dat de uitvoer UTF-8 is? Probeer eens er een utf8_encode() overheen te gooien.

Je zou ook eens kunnen kijken naar de mb_string functies in PHP. Ik had een soortgelijk probleem doordat ik met strtolower ed ging werken, welke niet multibyte zijn.
Perfect! utf8_encode heeft het probleem helemaal opgelost. Top! ;)

@RobIII: In de database staat alles op utf8_general_ci, lijkt me goed toch? Of moet ik een andere hebben?

Acties:
  • 0 Henk 'm!

  • Tsunami
  • Registratie: Juni 2002
  • Niet online
Wel een beetje een houtje touwtje oplossing. Er staan HTML entities in de database, wat al niet hoort. Gewoon plain text werkt prima. Vervolgens sloop je de UTF-8 character set met html_entity_decode, aangezien deze standaard op ISO-8859-1 staat (zie derde parameter). En vervolgens gooi je het doodleuk weer om naar UTF-8 met utf8_encode.

Oplossing: geen HTML entites in de database, dan heb je ook geen html_entity_decode en utf8_encode nodig (alleen htmlspecialchars als de tekst op een HTML-pagina komt te staan, wat hier niet het geval is).

Acties:
  • 0 Henk 'm!

  • bindsa
  • Registratie: Juli 2009
  • Niet online
Tsunami schreef op vrijdag 16 april 2010 @ 22:18:
Wel een beetje een houtje touwtje oplossing. Er staan HTML entities in de database, wat al niet hoort. Gewoon plain text werkt prima. Vervolgens sloop je de UTF-8 character set met html_entity_decode, aangezien deze standaard op ISO-8859-1 staat (zie derde parameter). En vervolgens gooi je het doodleuk weer om naar UTF-8 met utf8_encode.

Oplossing: geen HTML entites in de database, dan heb je ook geen html_entity_decode en utf8_encode nodig (alleen htmlspecialchars als de tekst op een HTML-pagina komt te staan, wat hier niet het geval is).
De reden is dat die entities in de database staan is dat het oude systeem input bij het opslaan in de database opsloeg als de entities ervan. Dat had toendertijd met beveiliging te maken. Ik snap dat we beter alleen htmlspecialchars konden doen i.p.v. htmlentities. Dat van die character set en html_entity_decode wist ik niet, bedankt daarvoor :P

Acties:
  • 0 Henk 'm!

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 09-09 16:17

Janoz

Moderator Devschuur®

!litemod

L0calh0st schreef op zondag 18 april 2010 @ 12:06:
Ik snap dat we beter alleen htmlspecialchars konden doen i.p.v. htmlentities.
Nee. Je moet je content escapen voor de context waarin deze wordt gebruikt. Dat iets als html afgedrukt wordt is pas van belang op het moment dat je html aan het afdrukken bent. Daar loop je nu onderandere tegenaan omdat je nu eerst je gewone content terug moet vertalen van html naar de text en daarna moet 'escapen' voor csv.

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!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
L0calh0st schreef op zondag 18 april 2010 @ 12:06:
[...]
Dat had toendertijd met beveiliging te maken. Ik snap dat we beter alleen htmlspecialchars konden doen i.p.v. htmlentities
Ik zie niet in hoe het encoderen van htmlspecialchars of htmlentities voordat je iets in een database stopt wat met beveiliging te maken hebben?

Zoals Janoz ook al aangeeft moet je alleen zorgen dat het voor je database in een goed formaat word aangeboden, en een database heeft niks met HTML te maken. Presentatie logica moet je pas op het moment doen dat je gaat presenteren.

[ Voor 28% gewijzigd door Woy op 18-04-2010 12:18 ]

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”

Pagina: 1