Fórum Ubuntu CZ/SK
Ubuntu pro osobní počítače => Obecná podpora => Téma založeno: josef_m 22 Října 2009, 17:37:31
-
Zdravím,
často zpracovávám soubory (prostý text, UTF-8) pomocí PHP skriptu, výsledek se ukládá do dalšího .txt souboru (UTF-8). Aniž bych něco měnil v nastavení Apache (kromě umístění složky pro localhost), "najednou" mi to výsledný soubor ukládá ve Windows CP1250, takže výsledek nepoužitelný. Nenapadá mě nic jiného, než souvislost s nějakou aktualizací Ubuntu? Má někdo podobný problém? Tip jak z toho ven?
V souboru "/etc/apache2/conf.d/charset" jsem zrušil komentář pro řádek "AddDefaultCharset UTF-8", restart Apache a nic...
Soubor "/etc/apache2/httpd.conf" je prázdný.
Měnil jsem jen umístění výchozí složky pro "localhost", ale to mám tak nastavené od začátku a vždy to jelo
-
Je ten skript vytvořen také v kódování UTF-8?
-
ano, v PSpadu jsem kontroloval jak výchozí soubor, tak i skript. Na netu jsem pár podobných problémů našel, ale pokud jsem dobře rozumněl, tak šlo o HTML dokumenty a tím pádem nutno upravovat hlavičku, ale u mě se jedná o "plaintext" soubory.
-
A jaké funkce používáš pro práci s textovými řetězci? obyčejné nebo multibyte?
-
Tos mě překvapil, já jsem netušil, že se to ještě nějak dělí.
Pro zajímavost skript připojuji níže; cíl skriptu: prostý textový soubor je zpracován tak, aby byl každý záznam (slovo, číslo či interpunkce) na novém řádku, a tím se získá výchozí dokument pro další zpracování (komentáře jsou ale německy, protože se jedná o česko-německý projekt)
Protože všechno donedávna fungovalo, tak mě nenapadlo hledat chybu ve skriptu, spíš Apache vs. aktualizace Ubuntu (?)
<?php
header('content-type: text/html; charset=utf-8');
print <<<EndOfHtml
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>W-liste-GR-de</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>
EndOfHtml;
// die zu bearbeitende Quelldatei - darf nicht geändert werden
// die Quelldatei für Wortliste wurde mit XSLT gewonnen als Plaintext File
//$startdatei = "grass_de_plaintext.txt";
$startdatei = "grass_de_ohne.txt";
$zieldatei = "grass_wortliste_ziel.txt";
if ( file_exists ($zieldatei)) {
unlink ($zieldatei);
}
////////////////////////// Start der Bearbeitung //////////////////////////////
if (! file_exists($startdatei)) {
echo "<b>Die Datei</b> \"$startdatei\" <b>existiert <font size=\"+1\" color=\"red\">NICHT</font></b><br /><br /><br />";
exit;
} else {
$fp = fopen ( $startdatei, 'r' ); // Name der Datei wird in die Variable $fp platziert - Pointer
$datei_inhalt = fread ( $fp, filesize ( $startdatei ) ); // die Datei wird eingelesen
fclose ( $fp );
}
$muster="/[ ]/";
$replace=" ";
$datei_inhalt = preg_replace($muster,$replace,$datei_inhalt);
$muster="/[\r\n]?[\r\n]?[\?|\!|\.|,|:|;|«|»|‹|›|„|“|…|\(|\)|\/|´|'|&|\"]/";
$replace="";
$erg = preg_replace($muster,$replace,$datei_inhalt);
///////////////////////////////////////////////////////////
// das folgende Ziel ist: die Wortgrenze wird durch einen Stern gekennzeichnet
$muster="/[\r\n][\r\n]|[\r\n]/"; // löscht die Leerzeilen
$replace=" ";
$erg = preg_replace($muster,$replace,$erg);
$erg = preg_replace("/ | | /"," ",$erg); // mehrere Leerzeichen zu einem
$erg = preg_replace("/\ /"," *",$erg);
// Wortende: 'Blank+Stern' - muss nicht sein, aber Stern wird bei Array Erstellung/Auflösung verwendet und Blank bleibt als Wortgrenze erhalten
//$erg = strtolower($erg); // wegen der Sortierung werden alle Anfangsbuchstaben kleingesetzt
///////////////////////////////////////////////////////////////
// Ziel hier: Array bilden
$array = split ( "\*", $erg );
//$element1 = array_shift ( $array ); // das erste Array-Element wird rausgenommen
sort ( $array ); // das Array wird alphabetisch sortiert
///////////////////////////////////////////////////////////////
// Ziel: sortierter Inhalt
$zaehle = array_count_values ( $array ); // berechnet, wie oft ein jeweiliges Wort vorkommt
while ( list ( $key, $val ) = each ( $zaehle ) )
{
$laenge = strlen ( $val ); // wegen Sortierung: misst die Länge von Inhalt der Variable $val
if ( $laenge == 1 ) { // wegen Sortierung: überprüft die Länge von $val, wenn 1, fügt drei Nullen hinzu
$val = ("000".$val);
}
if ( $laenge == 2 ) { // wegen Sortierung: überprüft die Länge von $val, wenn 2, fügt zwei Nullen hinzu
$val = ("00".$val);
}
if ( $laenge == 3 ) { // wegen Sortierung: überprüft die Länge von $val, wenn 1, fügt eine Null hinzu
$val = ("0".$val);
}
$erg_sortiert .= "$val " . " $key *"; // die zwei Ausgabewerte werden in eine Variable gesteckt
}
///////////////////////////////////////////////////////////////
// Ziel: sortiertes Ergebnis von Nummerieren weiter bearbeiten
$array_d_inhalt = split ( "\*", $erg_sortiert ); // erneut wird ein Array gebildet
//$element2 = array_shift ( $array_d_inhalt ); // das erste Array-Element wird rausgenommen
sort ( $array_d_inhalt ); // Sortierung des Arrays
foreach ( $array_d_inhalt as $array_d_zeilen ) { // das Array wird in Einzelementen gezeigt
$muster="/(?<=[0-9]{4})( )( )?/";
$replace="\t";
$array_d_zeilen = preg_replace($muster,$replace,$array_d_zeilen);
$zusammen .= "$array_d_zeilen" . "\r\n";
$muster="/( )( )?(?=[\r\n])/";
$replace="";
$zusammen = preg_replace($muster,$replace,$zusammen);
}
/////// ----------------------------
$fp = fopen ( $zieldatei, 'a+' );
fwrite ( $fp, $zusammen ); // schreibt den Inhalt von $erg in die neue Datei
fclose ( $fp ); // die Datei $wlnmrt wird geschlossen, erst hier, damit sie nicht nach jedem Eintrag getrennt geöffnet und geschlossen werden muss
?>
</body>
</html>
EDIT: promiňte, popis skriptu je zde špatně, to je předchozí krok, tento skript vychází z textového souboru, kde: co záznam to nový řádek. Cíl: abecední seznam slov (plaintext file), a u těch, která se opakují bude vypsáno, kolikrát se v textu vyskytují.
-
Řekl bych, že tvoje cesta vede přes PHP manuál, kapitola Multibyte String Functions. Nicméně preg_ funkce nepoužívám, použímám mb_ereg_, takže netuším, v čem jsou ty preg_ jiné...
-
Multibyte funkce s tím nemají dle mého soudu nemá nic společnýho. Ty jsou dobrý pro případ, že už pracuješ s nějakým multibyte řetězcem a ten ty zatím nemáš.
Spíš se zkus podívat do php.ini zda tam máš direktivu:
default_charset = "UTF-8"
-
kazdy "plaintext" je nejak kodovan... zkus se podivat jeste jinym editorem nez pspadem, ze ten PHP skript je skutecne v UTF-8. Napriklad geditem, phpeditem atd...
-
Samozřejmě, že každý plaintext je nějak kódován, já jsem také netvrdil, že ne. Ale multibyte funkce ti přeci nemění vstupní a výstupní kódování, takže jejich nasazením si nepomůžeš. Zmíněný php script otevře a přečte soubor $startdatei chybně v kódování CP1250 (tudíž ne multibyte) a ve stejném kódování jej pak zpracovaný i uloží. Je potřeba zajistit aby vstupní soubor byl již přečten v UTF-8 (a ve stejném pak i uložen). O to tu běží.
Je samozřejmě pravda, že když je předpoklad toho, že se bude pracovat s UTF, bylo by vhodné multibyte funkce používat, ale to není řešení stávajícího problému. Si myslim.
-
Bohouš: např. Geany ukazuje taky UTF-8
Iljusin: v php.ini jsem mel
;default_charset = "iso-8859-1"zmenil jsem to na
default_charset = "UTF-8"ale (i po restartu Apache) je to pořád stejné, tzn. cílový dokument má změněno kódování a já se nemůžu hnout z místa
-
Když si vypíšeš $datei_inhalt na obrazovku, je to ve správném kódování?
Když si vypíšeš $zusammen na obrazovku, je to ve správném kódování?
Když si dáš phpinfo(), vypíše ti to tam někde něco s 1250 (CP1250, Win1250, Win-1250) nebo nějakým ISO-8859?
-
Po vypsání obsahu uvedené proměnné na obrazovku:
- "$datei_inhalt" - všechny znaky v pohodě
(
- první problém u "$erg" (tj. po odstranění diakritiky) je špatně interpretováno přehlasované "u" ("ü") - malé i velké, jen na začátku slova, např. uprostřed slova je "ü" v pořádku (!), ostatní přehlásky jsou ok
(vyřazením tohoto kroku kupodivu skript text již nevidí, vypíše jen, že v celém textu je jen jednou "nic"; když bych místo vypsání všech těch interpunkčních znaků zadal "\W", tak to smaže i znak konce řádku, ale ten je tam ještě zapotřebí, proto jsem ty znaky vypisoval)
)
- "$zusammen" - stejně jak v předchozím kroku, tj. vše ok až na některé výskyty "ü"
- phpinfo() - na výstupu:
-> "1250" - nikde
-> ISO-8859 tady:
Apache Environment
HTTP_ACCEPT_CHARSET ISO-8859-2,utf-8;q=0.7,*;q=0.7
HTTP Headers Information
Accept-Charset ISO-8859-2,utf-8;q=0.7,*;q=0.7
iconv
Directive Local Value Master Value
iconv.input_encoding ISO-8859-1 ISO-8859-1
iconv.internal_encoding ISO-8859-1 ISO-8859-1
iconv.output_encoding ISO-8859-1 ISO-8859-1
PHP Variables
_SERVER["HTTP_ACCEPT_CHARSET"] ISO-8859-2,utf-8;q=0.7,*;q=0.7
-
Takže problém bude opravdu nejspíš v tom, že nepoužíváš mb funkce. Ty jsi psal, že výsledný soubor je v CP1250, ale asi to tak není, když se ti znaky (až na výjimky) zobrazují správně. Jak jsi vůbec přišel na to že je to v CP1250?
Dej na začátek skriptu
mb_internal_encoding("UTF-8");a pak používej mb_ prefix u stringových funkcí (mb_preg_replace, mb_strlen, ...) Uvidíš jestli to pomůže
-
Když si dám vypsat obsah proměnných na obrazovku, tak to je vlastně pořád výchozí soubor, byť upravený. Cílový soubor vzniká až v posledním kroku skriptu a na obrazovce nic není. Když otevřu cílový soubor (např. v PSpadu), tak je kódování zvláštních znaků totálně rozhozené a v liště je vidět, že se jedná o CP1250.
Ty mb funkce hned vyzkouším.
-
... tak je kódování zvláštních znaků totálně rozhozené a v liště je vidět, že se jedná o CP1250
No a to je právě chybný úsudek. Pakliže na začátku plaintextu není značka která by natvrdo řekla o jaké jde kódování (BOM), tak PSpad jeho kódování pouze odhadne. V případě tvého souboru to odhadl špatně (kvůli některým "rozbitým" znakům) a otevřel jej jako CP1250. Kdybys mu vnutil otevřít to jako UTF8, předpokládám, že se ti obsah zobrazí stejně jako když si výstup vyplivneš v PHP scriptu rovnou na obrazovku, tj., že většina znaků je správně. Tím chci říct, že tvůj výstupní soubor je stále v UTF8, ale díky tomu, že jsi nepoužil mb funkce, tak ti to některé znaky rozbilo (a PSPad je z toho zmatený).