Usiłuję wyświetlić e-maila (ISO-8859-2) pobranego przez IMAP ale mam
problem ze znakami narodowymi.
Strona HTML na której umieszczam zawartość e-maila ma kodowanie UTF-8
Robię coś takiego:
$body = imap_fetchbody($inbox,$id, 1);
$struckture = imap_fetchstructure($inbox, $id);
$coding = $struckture->parts[1]->encoding;
$coding jest NULL lub jest równe 0.
Próbowałem użyć imap_utf8($body) ale nie ma polskich znaków.
Testowo zrobiłem mb_convert_encoding($body,"UTF-8", "ISO-8859-2")
Jest dużo lepiej ale części znaków nadal brak.
Co trzeba zrobić aby poprawnie wyświetlać e-maila ?
Paweł
> Testowo zrobiłem mb_convert_encoding($body,"UTF-8", "ISO-8859-2")
> Jest dużo lepiej ale części znaków nadal brak.
> Co trzeba zrobić aby poprawnie wyświetlać e-maila ?
ISO jest w stanie przedstawić tylko ok. 200 znaków z ok. 100000, które
obsługuje UTF-8. Konwersja Unicode na archaiczne kodowanie zawsze wiąże
się z ryzykiem utraty znaków.
Najlepiej przestaw stronę na UTF-8 (konwersja ISO → UTF-8 jest bezstratna).
W HTML da się uratować sytuację za pomocą encji: htmlentities($txt,
ENT_QUOTES, 'UTF-8');
--
http://pornel.net
this.author = new Geek("porneL");
Stronę HTML mam UTF-8. Generuje ja w skrypcie PHP
header ("Content-type: text/html; charset=UTF-8");
...
echo '<head><meta http-equiv="Content-Type" content="text/html;
charset=UTF-8" /></head>';
> W HTML da się uratować sytuację za pomocą encji: htmlentities($txt,
> ENT_QUOTES, 'UTF-8');
>
Zrobiłem teraz:
$body = imap_fetchbody($inbox,$id, 1);
$body=htmlentities($body, ENT_QUOTES, 'UTF-8');
echo nl2br($body);
Nadal nie ma polskich znaków
Jeśli zrobię imap_body($inbox,$id) zamiast imap_fetchbody($inbox,$id,
1); to na początku otrzymuję:
This is a multi-part message in MIME format.
--------------080706030701080000000507
Content-Type: text/plain; charset=windows-1250; format=flowed
Content-Transfer-Encoding: 8bit
Testowo przepuściłem to przez skrypt zamieniający znaki "windows-1250"
->UTF-8 i polskie znaki się pojawiły.
Paweł
> Stronę HTML mam UTF-8. Generuje ja w skrypcie PHP
> header ("Content-type: text/html; charset=UTF-8");
Ah, sorry. Źle przeczytałem.
Jak wyglądają niedziałające znaki? Nagłówek content-type jest w e-mailu?
Ekhm...
$body na początku zawiera coś takiego:
This is a multi-part message in MIME format.
--------------080706030701080000000507
Content-Type: text/plain; charset=windows-1250; format=flowed
Content-Transfer-Encoding: 8bit
------ Wiadomo�� oryginalna ------
W przeglądarce (FF) wygląda to identycznie jak w tym e-mailu. Brak "ś",
"ć" w wyrazie "Wiadomość". Zamiast nich jest prostokąt z FF,FD.
Jak już pisałem wcześniej jeśli zawienię kody znaków narodowych w $body
z windows-1250 na UTF-8 to jest OK.
Dodanie instrukcji:
$body=htmlentities($body, ENT_QUOTES, 'UTF-8');
Zupełnie nic nie zmienia.
E-maile wysyłane jako tekstowe nie zawierają nagłówka i z nimi nie
mailem problemów.
Paweł
Dostrzegasz jakiś trop, Szerloku?
> Jak już pisałem wcześniej jeśli zawienię kody znaków narodowych w $body
> z windows-1250 na UTF-8 to jest OK.
Coś Ty? To jaki masz problem?
Poza tym, chrząkanie moje nawet nie pomogło... więc właściwie to sobie
idę :)
Czy metoda przedstawiona poniżej będzie dobra ?
1. odczytać nagłówek przez imap_fetchheader
2. przeszukać nagłówek pod kątem występowania ciągów znaków
określających różne sposoby kodowania.
3. odczytać e-maila przez imap_fetchbody
4. pozamieniać odpowiednio kody znaków
Paweł
Nie da się ukryć, że odczytanie treści maila a potem konwersja
kodowania jest dobrym sposobem. Tylko, że atrybut encoding nie ma nic
wspólnego z UTF8, CP1250 ani ISO-8859-2. Co prawda mógłbym napisać od
razu o co mi chodzi, ale mi się nie chce, skoro Tobie nie chce się
zajrzeć do manuala i przeczytać opis tych funkcji.
Masz jakieś pomysły, dlaczego to nie działa? ;)
Treść maila jest zakodowana w np. CP1250, ale później jest jeszcze w
jakiś sposób kodowana, np. quoted printable i to jest wysyłane jako
mail.
Aby to prawidłowo odczytać, to należy odkodowac w drugą stronę, więc:
QP CP1250 -> CP1250
To kodowanie transmisji (Body transfer encoding) określane jest
właśnie w atrybucie encoding.
Transfer encodings (may vary with used library)
0 7BIT
1 8BIT
2 BINARY
3 BASE64
4 QUOTED-PRINTABLE
5 OTHER
Więc po ściągnięciu wiadomości, trzeba najpierw to odkodować za pomocą
np. http://www.php.net/manual/en/function.imap-qprint.php. Druga
popularna metoda kodowania, np. załączników to base64.
Jeśli mówisz, że tam masz zero, tzn. że masz to w 8-bit, a co za tym
idzie to sobie poszukaj, np. tu http://msdn.microsoft.com/en-us/library/ms526992(EXCHG.10).aspx
Kodowanie znaków natomiast kryje się w parametrze charset i jest to, o
ile dobrze pamiętam, w tablicy właśnie parameters. Zrób sobie
var_dumpa tego, co zwraca imap_fetchstructure, to będziesz wiedział. W
Twoim przypadku charset powinien być równy windows-1250 (cp1250). Za
pomocą iconv() możesz to sobie zamienić na utf-8, ale! z konwersją z
cp1250 mogą być kłopoty (parę razy mi się zdarzyło, że dostawałem
nulla), więc lepiej staraj się wysyłać maile w ISO, albo UTF - jeśli
masz na to wpływ.
Generalnie, to zabawa z mailami jest dużo trudniejsza niż to się
wydaje - głównie chodzi o masę maili niespełniającą standardów.
Null natomiast to zje*any mail ;]
W sieci są setki bardzo podobnych przykładów.
Dla wartości zero we wszystkich jest do odkodowania użyta funkcja
imap_7bit. Jednak w nowszych wersjach PHP już jej nie ma
Metodą prób i błędów doszedłem, że trzeba użyć imap_qprint lub
quoted_printable_decode
To co napisa�e� bardzo mi pomog�o. Skrypt ju� dzia�a.
Cho� nie wiem czy zawsze imap_fetchheader zwr�ci tekst, z kt�rego b�dzie
mo�na uzyska� informacj� o kodowaniu.
Te e-maile, dla kt�rych encoding jest NULL to klasyczne wiadomo�ci tekstowe.
Paweďż˝
Zdradź jeszcze jak pewnie uzyskać informację o zastosowanym kodowaniu.
Właśnie odebrałem e-maila gdzie imap_fetchheader zwraca tekst, w którym
nie ma ciągu określającego kodowanie.
Paweł
Nie da się. Ale można strzelać z mb_detect_encoding();
Pokaż takiego przykładowego maila. Możesz zamazać treść i nadawców/
odbiorców.
Nie musisz wykrywać kodowania za pomocą parsowania nagłówków (choć
możesz) - w zwrotce imap_fetchstructure() jest atrybut parameters (i
dparameters czy coś tam) - to jest tablica z parametrami, jeden z nich
to charset (pisane tak jak w mailu, czyli albo charset albo CHARSET, a
jak ktos ma fantazje to i charSET itp.).
E-maila można wysłać jako HTML lub jako tekst.
W pierwszym przypadku funkcja imap_body na początku zwraca np. coś takiego:
This is a multi-part message in MIME format.
--------------080706030701080000000507
Content-Type: text/plain; charset=windows-1250; format=flowed
Content-Transfer-Encoding: 8bit
Dalej jest zawartość wiadomości (tekst).
W drugim przypadku jest tylko zawartość wiadomości. Nie ma nic więcej.
Zauważyłem, że dla tych tekstowych wiadomości
$struckture->parts[1]->encoding zwraca NULL.
Trochę inaczej również wygląda również to co zwraca imap_fetchheader.
Jak trzeba to mogę coś przesłać jednak nie wiem co dokładnie mam zrobić.
>w zwrotce imap_fetchstructure() jest atrybut parameters (i
> dparameters czy coś tam) - to jest tablica z parametrami, jeden z nich
> to charset (pisane tak jak w mailu, czyli albo charset albo CHARSET, a
> jak ktos ma fantazje to i charSET itp.).
Zrobiłem to tak:
$struct = imap_fetchstructure($inbox,$id);
$charset =$struct->parts[0]->parameters[0]->value;
Wszytko działa.
Bardzo dziękuję za pomoc.
Paweł
To jest bardziej pokręcone. Możesz mieć zagnieżdżenia partów. Więc
trzeba rekurencyjnie to sprawdzać. W dodatku każdy part może mieć osobne
kodowanie. Tak ogólnie to bajzel na kółkach, w dodatku każdy klient mail
(szczególnie webmaile) tworzą radosną twórczość dzieci kalekich.
--
wer <",,)~~
http://szumofob.eu