Autor Zpráva
truefriend-cz
Profil
Ahoj. Mám script, který se připojuje na server IMAP Gmailu a zobrazuje zprávy. Ale některé z nich jsou "rozsypaný text".
Když příjde mail s kódováním:
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: base64
tak se zobrazí v pořádku.

Když však příjde:
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: quoted-printable

tak se ukáže původní text "Dobrý den, soidugsodugoauíášýěířěýšř" jako "��7^��"v�,�۠��� M}P�@��@���m��ݭ�ޘƫi'���O���rٚ�[h��ڱ�r&j)\�".

Na internetu jsem našel script2.php, který by měl tohle řešit ale nedaří se mi ho začlenit do script1.php tak, aby fungoval.

Pomohl by mi někdo s tím?

Jinak výsledný požadavek je takový, aby když přijde email ať s TEXT/HTML nebo TEXT/PLAIN obsahem tak aby se zobrazoval jen jako prostý text ve formátu "Jméno odesílatele, Datum odeslání zprávy, a Tělo zprávy". (což momentální verze script1.php dělá) i když těžko říct, protože HTML emaily co mám ve schránce přímo od Google mají "Content-Type: text/plain". Akorát to tedy zlobí s tím rozsypáním textu.

script1.php:
<?php

$hostname = '{imap.gmail.com:993/imap/ssl}INBOX';
$username = '*******@gmail.com';
$password = '***********';
$imap_client = imap_open($hostname, $username, $password);

if (!$imap_client) {
    echo imap_last_error();
    exit;
}

$emails = imap_search($imap_client, 'ALL');

if (empty($emails)) {
    echo 'Ve schránce se nenacházejí zprávy.';
} else {
    foreach ($emails as $email_id) {

        $text = imap_fetchbody($imap_client, $email_id, '1');
        $text = base64_decode($text);

        $header = imap_header($imap_client, $email_id,'1');
        echo '<div class="container"><div class="container-in from">' . imap_utf8($header->fromaddress) . '</div>' . ' <div class="container-in date">(' . date("d. m. Y", $header->udate) . ')</div></div>';

        echo '<div class="body">⋙ ' . $text. '</div>';
        echo '<br><br>';
    }
}

imap_close($imap_client);
?>

script2.php:
<?php
function getBody($uid, $imap) {
    $body = get_part($imap, $uid, "TEXT/HTML");
    // if HTML body is empty, try getting text body
    if ($body == "") {
        $body = get_part($imap, $uid, "TEXT/PLAIN");
    }
    return $body;
}
function get_part($imap, $uid, $mimetype, $structure = false, $partNumber = false) {
    if (!$structure) {
           $structure = imap_fetchstructure($imap, $uid, FT_UID);
    }
    if ($structure) {
        if ($mimetype == get_mime_type($structure)) {
            if (!$partNumber) {
                $partNumber = 1;
            }
            $text = imap_fetchbody($imap, $uid, $partNumber, FT_UID);
            switch ($structure->encoding) {
                case 3: return imap_base64($text);
                case 4: return imap_qprint($text);
                default: return $text;
           }
       }
        // multipart 
        if ($structure->type == 1) {
            foreach ($structure->parts as $index => $subStruct) {
                $prefix = "";
                if ($partNumber) {
                    $prefix = $partNumber . ".";
                }
                $data = get_part($imap, $uid, $mimetype, $subStruct, $prefix . ($index + 1));
                if ($data) {
                    return $data;
                }
            }
        }
    }
    return false;
}
function get_mime_type($structure) {
    $primaryMimetype = array("TEXT", "MULTIPART", "MESSAGE", "APPLICATION", "AUDIO", "IMAGE", "VIDEO", "OTHER");
    if ($structure->subtype) {
       return $primaryMimetype[(int)$structure->type] . "/" . $structure->subtype;
    }
    return "TEXT/PLAIN";
}
?>
Kajman
Profil
Zkuste nahradit řádky
$text = imap_fetchbody($imap_client, $email_id, '1');
$text = base64_decode($text);
řádkem
$text = getBody($email_id, $imap_client)

Funkce ze script2 je potřeba nějak načíst, např. na začátku skriptu1 příkazem
require_once("script2.php");
truefriend-cz
Profil
truefriend-cz, Kajman:
bohužel to nepomohlo. Začalo to vypisovat chybu, kterou to dělat nemá, protože by měla být ošetřená.
Chyba je Fatal error: Uncaught Error: Using $this when not in object context in script.php:64 Stack trace: #0 script.php(148): getBody(1, Resource id #2) #1 {main} thrown in script.php on line 64

Jinak vložil jsem ten obsah script2.php do toho souboru jen jako funkci. Nebudu to volat ještě z jiných scriptů.
Jinak řádkem 63 začíná "function getBody($uid, $imap) {".
Před tímto řádkem mám jen CSS styl.

Zkusil jsem najít novější (snad lepší) verzi těch funkcí (odstraněné je jen to "$this->"):
function getBody($uid, $imap) {
    $body = get_part($imap, $uid, "TEXT/HTML");
    // if HTML body is empty, try getting text body
    if ($body == "") {
        $body = get_part($imap, $uid, "TEXT/PLAIN");
    }
    return $body;
}
function get_part($imap, $uid, $mimetype, $structure = false, $partNumber = false) {
    if (!$structure) {
           $structure = imap_fetchstructure($imap, $uid, FT_UID);
    }
    if ($structure) {
        if ($mimetype == get_mime_type($structure)) {
            if (!$partNumber) {
                $partNumber = 1;
            }
            $text = imap_fetchbody($imap, $uid, $partNumber, FT_UID);
            switch ($structure->encoding) {
                case 3: return imap_base64($text);
                case 4: return imap_qprint($text);
                default: return $text;
           }
       }
        // multipart 
        if ($structure->type == 1) {
            foreach ($structure->parts as $index => $subStruct) {
                $prefix = "";
                if ($partNumber) {
                    $prefix = $partNumber . ".";
                }
                $data = get_part($imap, $uid, $mimetype, $subStruct, $prefix . ($index + 1));
                if ($data) {
                    return $data;
                }
            }
        }
    }
    return false;
}
function get_mime_type($structure) {
    $primaryMimetype = array("TEXT", "MULTIPART", "MESSAGE", "APPLICATION", "AUDIO", "IMAGE", "VIDEO", "OTHER");
    if ($structure->subtype) {
       return $primaryMimetype[(int)$structure->type] . "/" . $structure->subtype;
    }
    return "TEXT/PLAIN";
}

function truncate($str,$n_chars='240',$crop_str=' ... <div class="info">(text byl zkrácen)</div>')
{
    $buff=strip_tags($str);
    if(strlen($buff) > $n_chars)
    {
        $cut_index=strpos($buff,' ',$n_chars);
        $buff=substr($buff,0,($cut_index===false? $n_chars: $cut_index+1)).$crop_str;
    }
    return $buff;
}
ale to zase vyhazuje chybu:

Warning: imap_fetchstructure(): Bad message number in script.php on line 11 (číslo řádku jsem upravil pro použití tady).

Jinak když jsem si nechal ve funkci před řádkem 11 vypsat na stránce přes echo hodnotu $uid tak ji to normálně přiděluje správně.
Kajman
Profil
Když ty funkce používají k číslování UID, tak by i imap_search měl být volaný s příznakem, aby to používal.

$emails = imap_search($imap_client, 'ALL', SE_UID);
truefriend-cz
Profil
Vyzkoušel jsem to a až na několik chybových zpráv okolo se načítá i obsah ale neumí to zobrazit HTML e-maily jako prostý text. Respektive zobrazuje to jako prostý text ale ne ten text na stránce jako když to bylo z původního script1.php
Zobrazuje se včetně CSS, aj. obsahu v HTML mailu. "@media only screen and (max-width: 767px){ .body_wrapper{min-width:100vw !important;} .device_txt{font-size:26px!imp"...

Zkoušel jsem ve funkci vyměnit imap_base64, imap_qprint, za (původně fungující u HTML e-mailů) base64_decode ale to problém neřeší (rozházeně zobrazuje jak HTML maily tak i maily v prostém textu). V této úrovni jsem nenašel jak nějakou funkci tak třídy, které by byli schopny reálně pracovat s diakritikou tak aby výsledkem bylo co požaduji.

A další chyba, že se u emailů začalo objevovat datum odeslání 01. 01. 1970.

Zkouším ještě na netu hledat nějaké řešení ve směru "mail to rss", které by se dalo pro to co chci možná lépe použít. Pokud víte o něčem takovém existujícím o čem víte, že by mělo nebo funguje s češtinou bylo by to fajn.

Z toho co jsem našel například: github.com/vekin03/Mail2RSS
Zjišťuji, že to co je na netu je mnohdy staré a nefunguje to kvůli zastaralosti a nevěnování se chybám v kódu (podpora autorů těch scriptů nereaguje).

Zmíněné chyby jsou (zde z uvedeného jako script1.php):
Warning: imap_header(): Bad message number in script.php on line 23

Notice: Trying to get property 'fromaddress' of non-object in script.php on line 24

Notice: Trying to get property 'udate' of non-object in script.php on line 24

Po čarou:
Nikdy jsem netušil, že taková hovadina typu zobrazit e-maily v úplně základní variantě textu bude taková patálie. Už se s tím **** týden. Hledám stále nějaké classy, postupuji podle českých návodů "krok za krokem" a nechápu jak tihle experti i na profesionálních webech kde jsou ty průvodci opomíjejí takové základy aby se vůbec text zobrazil ve správné codepage, apod. Cca ze 80% vůbec nějaké kódování nebo řazení podle nějakého parametru jako datumu, apod. naprosto neberou v úvahu. A když člověk něco takového najde, tak nakonec musí překopat celý kód, protože to nestaví tak, aby to bylo pokud možno integrované na další funkce. Ty peníze za reklamu na těch webech bych jim narval kamsi...
Kajman
Profil
truefriend-cz:
Ty peníze za reklamu na těch webech bych jim narval kamsi

Ano, to je také možnost, nabídnout jim peníze za zakázku na míru s jasným zadáním a placenou podporou po nějakou dobu od předání.
Tomášeek
Profil
truefriend-cz:
Proč se rozčiluješ, že někdo nenabízí podporu k něčemu, co ve svém volném čase napsal a dal volně na internet k užití?

Ty sám jsi někdy zadarmo na internet pověsil něco, co bylo k užitku i ostatním? A po letech, když ti někdo napsal mail, že něco nefunguje, jsi nechal veškeré práce, sedl ke stroji a během hodiny, dne, týdne danou funkcionalitu někomu na míru připravil? Zdarma samozřejmě? Asi ne, že? Nic ti nebrání nabrat potřebné zkušenosti a napsat vlastní třídu, která bude fungovat dokonale. Nebo si najmout někoho, kdo to napíše za tebe, pokud na to sám nemáš.

Řešíš úplně základní chyby špantého formátování data (předpokládám, že datum je ve zprávách správné), non-object, atd. Čílíš se, že ti funguje jen HTML výpis, ale ne plaintext. Plaintext se z HTML zprávy dá udělat i bez užití nějaké třídy, zabralo mi to asi tak půl minuty.
Davex
Profil
Moderátor Davex: Přesunuto z duplicitního smazaného tématu.

E-maily mohou být poskládané různými způsoby nebo různě zakódované, takže nikdy nemůžeš spoléhat na to, že v části 1 bude vždy text zakódovaný v base64. Z obálek je nejdřív potřeba vyčíst strukturu pomocí imap_fetchstructure a v ní najít správnou část a způsob jak získat obsah.

Jinak to nemá smysl řešit takto nízkoúrovňově, když existují knihovny jako třeba PhpImap.
N71
Profil *
Odborná poznámka k původnímu tématu: IMAP, respektive v tomto případě MIME, je jedna z nejstarších široce používaných internetových komunikačních norem – A v takové je zhruba taky kondici. Bezchybnou implementaci neumí udělat už vlastně nikdo, ten formát se už dávno vymknul kontrole a kompatibilita je samozřejmě víc než norma. Obecně je to tedy úkol netriviální a rozhodně bych radši hledal hotovou knihovnu, než se pokoušel o cokoliv sám.


Moderátor Kajman: Vlákno je promazáno od nesouvisejících blábolů uživatele truefriend-cz a reakcí na ně. Pokud bude uživatel truefriend-cz nadále spamovat diskuzi výlevy mimo zaměření diskuze a zakládat duplicitní vlákna, dostane ban.

Vaše odpověď

Mohlo by se hodit


Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm:

0