PHP, konvertering av teckenkodning

Permalänk

PHP, konvertering av teckenkodning

Hej,
Är lite grön på teckenkodning (och även på html, php o webläsare)och behöver lite hjälp här. Måste fixa detta.

Har en sträng (en fil egentligen) som skrivs ut m.h.a nl2br(file_get_contents(<filnamn>)) och åäö blir korrekt på skärmen. Som jag minns det (sitter hemma nu o har inte koden på denna dator) så skriver jag UTF-8 i en header() först.
Nu till problemet, samma fil ska sen laddas ner till klienten, den laptop/smartphone som kommunicerar med php-sidan via Apache2. Men den filen innehåller ju två tecken per svenskt tecken. Jag antar det är det som är teckenkodningen o i detta fall UTF-8? När den filen sedan öppnas i Excel eller nåt annat enklare så blir ju svenska tecknen felaktiga. De består av 0xc3 och sen typ 0xa5 eller nåt beroende på vilket svenskt tecken det är.
Nu ska det finnas en teckenkodningskonverterare i PHP som heter mb_convert_encoding(). Kan det var nåt att konvertera strängen(filen) med innan den skrivs ut/skickas till klienten? Men hur ska parametrarna se ut till denna mb_convert.... ? Jag antar att det handlar om utökad ascii?

Tacksam för hjälp.

Permalänk
Medlem

Exel är ett stenåldersprogram som fortfarande inte kör unicode. Du kan köra någon form av importeringssteg i Exel för att konvertera till en exel fil. Om du ska bygga en sida som skapar exel-filer gör du bäst i att använda något färdigt PHP-bibliotek.

Permalänk

Jo. Det där med Excel vet jag. Men själva filen är problemet. Om jag öppnar filen i notepad är det som ni förstår samma problem. Åäö är fel. Jag behöver ha ett svenskt tecken där istället för dessa två tecken... Funkar inte med en konversation efter nerladdning. Kunden blir galen om ett ytterligare steg krävs för att se filen i Excel eller typ notepad.
(det handlar om ett par rader text med några kolumner med floats. Texten måste se riktig ut)

Skickades från m.sweclockers.com

Permalänk
Geeks
Jobbar med data

Vad har du för teckenkodning på alla dina filer? I t.ex. Notepad++ så ser man det längst ner till höger. Skall stå UTF-8 inuti ALLA filer.

Konvertera till UTF-8: Encoding -> Convert to UTF-8

Glöm inte bort att specificera <meta charset="utf-8"> inuti din <head> tagg i HTML koden för att få rätt inmatningar. Och även PHP:

header('Content-type: text/html; charset=utf-8');

Du kan validera att dina strängar är UTF-8 med hjälpa av:
http://php.net/manual/en/function.mb-detect-encoding.php

Själv exporterar jag till csv såhär:

ob_start(); ob_clean(); header("Content-Disposition: attachment; filename=\"export.csv\""); header("Content-type: application/csv; charset=utf-8"); header("Pragma: cache"); header("Cache-Control: public, must-revalidate, max-age=0"); header("Connection: close"); header("Expires: ".date("r", time()+60*60)); header("Last-Modified: ".date("r", time())); header("Content-length: ".strlen($file)."\r\n"); echo $file; ob_flush(); exit();

Du kan alltid kolla vilken som är standardteckensnitt i kundens Excel och sedan konvertera med mb_convert_encoding, som du skrev om tidigare.
Om jag inte missminner mig använder Excel Windows-1252.

mb_convert_encoding($str, "Windows-1252", "UTF-8");

Permalänk

Tack. Den där headern du angett ovan är snarlik den jag har och när jag läser in min rapport_xxx.csv i MS Word så frågar den om texten är UTF-8. Accepterar jag så ser filen korrekt ut i Word. Men som sagt, Excel (som jag behöver för dess funktionalitet, därav CSV) visar upp text-avsnittet ovanför flyttals-datat felaktigt. Där tror jag "Windows-1252" kan vara lösningen. Måste testa idag...men va f*n, det är ju Långfredag!! Måste på jobbet...

För övrigt, jag provade str_replace() vilket jag använder mig av på ett annat ställe. Men insåg snabbt att det inte var så enkelt att ersätta två tecken med ett utan att göra en massa extra jobb. Då drog jag mig till minnes just denna mb_convert_encoding.
Om jag ska dra storyn bakom str_replace() så ersätter den underscores med mellanslag EFTER att jag visat upp rapporten på (telefon)skärmen och innan den skrivs till klienten som en fil. Orsak? Jag använder mig av Courier vid utskrift på skärm MEN mellanslag blir inte fulla teckensnittsbredder så kolumnerna med floats blir ändå inte riktigt högerjusterade trots %' 10.2f..... detta "mellanslag" har jag fått lov å ersätta i all hast med underscore. Suck. För lite tid att fixa allt...

Tack hur som helst för hjälpen.

Permalänk
Legendarisk

@Sweedland: Först: Om det handlar om en csv så ska du inte använda nl2br() på outputen eftersom att det ersätter alla radbrytningar med <br/>-taggar; har det sett riktigt ut på skärmen så har du antagligen tittat på dokumentet som om det vore html snarare än text/csv, och då är inte din csv rätt formaterad.

Sedan till teckenkodningen: Eftersom att du ser två tecken istället för åäö och du har fått fram att de består av x'C3A5 (litet å i UTF-8) etc. så låter det som att din data är UTF-8, men Excel har antagligen tolkat den som Windows-1252. Använde du den vanliga filöppningsdialogen? IIRC så låter den dig inte välja teckenkodning själv, men du kan prova Data > From Text och välja UTF-8 som första steg i wizarden istället. För att göra det lättare för din användare, och om all din data går att representera i Windows-1252 (som bör vara default för en västeuropeisk excelinstallation), så kan du konvertera till det så här (som i @jreklund's svar):

header("Content-Type: text/csv; charset=windows-1252"); $data = file_get_contents("/din/fil/kodad-som-utf8.csv"); $data = mb_convert_encoding($data, "windows-1252", "UTF-8"); echo $data;

Använd inte str_replace för att försöka konvertera mellan teckenkodningar, det blir mycket mer att skriva och det kommer uppstå missar även med trivial förväntad input (det finns t.ex. flera olika sätt att representera ett litet å). Glöm inte att uppdatera din Content-Type-header så att resultatet visas som det ska i webbläsaren också.


Teckenkodningsproblem är notoriskt svåra att felsöka utan att se data och process. Om ovanstående inte skulle lösa problemet så skulle det hjälpa om du kunde dela din kod och representativ data (var försiktig med hur du kopierar så att du inte råkar konvertera något på vägen).

Visa signatur

Abstractions all the way down.

Permalänk

Jag kan kopiera in de väsentliga delarna av koden. Det är mycket mumbo-jumbo förövrigt.

Jag använder nl2br() när jag skickar filen till skärmen.

$out_put = nl2br(file_get_contents(RAPPORT_KATALOG.RESULTAT_RAPPORT_TEMP)); echo "<div style = 'font-family:courier;font-size:75%;color:#4444FF;'>$out_put</div>";

I html-delen:

<meta http-equiv="Cache-control" name="viewport" content="width=device-width, initial-scale=1, No-Cache">

Här kan användaren se rapporten på skärmen. Vill han ladda ner den så kan han klicka på en knapp så laddas en annan PHP in som ser ut som följer:

$fsize= filesize($rappCSVNamn); header('Contect-Description: File Transfer'); header('Content-type: text/csv; charset=UTF-8'); header('Content-disposition: attachment; filename="'.$rappCSVNamn.'"'); header('Expires: 0'); header('Cache-Control: must-revalidate'); header('Pragma: public'); header('Content-length: '.$fsize); ob_clean(); flush(); $fd=fopen($rappCSVNamn,"r"); while(!feof($fd)) { $sss=fgets($fd); $sss = str_replace(["_"], [" "], $sss); echo $sss; #här vill jag använda converteringen!! //echo "<div style = 'font:Courier;color:#ff0000'>$out_put</div>"; } fclose($fd); ob_start();

Du kan säkert hitta fler galenskaper här men pga tvång, tidsnöd o okunskap så blir det så här. Men skam den som ger sig!

Tack.

Redigerat in [code]-taggar //Mod
Permalänk
Legendarisk

@Sweedland:

  • Storleken kan ändras vid konvertering mellan teckentabeller så du måste avvakta med det steget till dess att du vet exakt vad som ska skickas.

  • Om du bara behöver göra en ersättning så kan du ge str_replace() enkla strängar istället för arrayer (se exempel nedan).

  • Filnamnsparametern till Content-Disposition kan kräva extra omtanke om det är annat än enkel, alfanumerisk ASCII.

  • Anropen till ob_clean() / flush() ska inte ha någon effekt. Kan det finnas data i en buffert innan du skriver ut uppgifterna från csv:n? Varför? Om inte kan det tas bort. För flush(): Varför flusha om det inte finns något att skicka än, och om tidigare output var buffrat och nu rensat? Se även ob_flush(). Antagligen vill du bara ta bort de här två raderna.

  • AFAIK så är inte Content-Description en standardheader i HTTP.

  • Även om det alltid är suspekt att göra strängersättningar utan hänsyn till hur datan är strukturerad (t.ex. över hela rader eller filer istället för per fält i en csv) så kan du bespara dig en del skrivande genom att använda dig av file_get_contents() istället för fopen() etc.

<?php $data = file_get_contents($rappCSVNamn); // Läs in filen. $data = mb_convert_encoding($data, "windows-1252", "UTF-8"); // Konvertera till windows-1252. $data = str_replace("_", " ", $data); // Naiv ersättning av "_" med " ". // $fsize = strlen($data); // Nu vet vi hur mycket som ska skickas. header("Content-Type: text/csv; charset=windows-1252"); header("Content-Length: ".$fsize); // Varning: kan vara fel beroende på namnets format: header("Content-Disposition: attchment; filename=\"".$rappCSVNamn."\""); header('Expires: 0'); header('Cache-Control: no-cache'); header('Pragma: no-cache'); echo $data;

Skrivet av Sweedland:

Men skam den som ger sig!

+1

Visa signatur

Abstractions all the way down.

Permalänk

Ok. Du tänker så. Filen är en enkel ascii med svenska tecken btw.
Jag hade problem med att filen skrevs till klienten men även buffert från html-koden. Så jag googlade lite och fick det där som exempel. Har inte grottat ner mig mer i det. Det började fungera så jag lade det åt sidan fram tills jag stötte på patrull med åäö.

Du har bakat om koden lite. Jag inser ju att det funkar också. Varför jag använder "no-cache" beror väl på att jag haft problem med att web-läsaren vägrar läsa om koden...f*n vet. Mycket har gått på rus ska du veta..
fopen användes för jag är van det sen C-programmen...byter gärna ut det.

Jag ska åka ner nu o testa lite.
Tack.

//edit
Åkte ner o testade. Har bakat om koden enligt sista inlägget OCH använt mig nu av mb_convert. Testat och det fungerar! TACK << 8.

Permalänk
Legendarisk
Skrivet av Sweedland:

Filen är en enkel ascii med svenska tecken btw.

Vet inte om jag förstår dig rätt, men om *filnamnet* kan innehålla svenska vokaler så är det inte ASCII; det är en 7-bitarskodning som inte kan beskriva de tecknen. Kan du garantera att filnamnen bara innehåller tecken som förekommer i den länkade tabellen (och att det följer specifikationen i övrigt, och att de är giltiga för mottagarens filsystem) så är det OK, annars behöver du antingen skicka ett substitut eller koda om filnamnet. Här finns en diskussion med mer information om det:
http://stackoverflow.com/questions/93551/how-to-encode-the-fi...

Visa signatur

Abstractions all the way down.

Permalänk

Ne. Du har rätt. Jag tänkte på det när jag åkte ner. ASCII är det inte.

Hela systemet med server/klient är under full kontroll och filnamn o innehåll är styrt av mig.
Jag ska läsa länken. Tack igen.