Partage
  • Partager sur Facebook
  • Partager sur Twitter

Lecture des mails avec IMAP

    16 avril 2024 à 12:00:10

    Bonjour,

    Je tente de créer moi-même un webmail basé sur IMAP.

    J'arrive à bien récupérer les images à l'intérieur du body ainsi que les attachements. Mais je rencontre deux soucis :

    mb_convert_encodin($bodymsg, "UTF-8", "auto") ne semble pas marcher avec ISO-8859-1

    Malgré imap_fetchbody j'obtien souvent plusieurs part dans mon body dont le message en plain text, le message en base64 et parfois les fichiers

    Pouvez-vous m'aider à corriger ces problèmes ? 

    à toutes fins utiles mon code : 

    /**
         * @Route("/email/read/id={id}", name="email_read", methods={"GET", "POST"})
         * @IsGranted("ROLE_USER")
         */
       public function readInbox(Request $request, Imap $imap, $id, Packages $assetPackage): Response {
        $mbox = $this->logImap("");
    
        if ($mbox === false) {
            die('La connexion a échoué. Vérifiez vos paramètres!');
        } else {
            $uid = $id;
            $structure = imap_fetchstructure($mbox, $uid, FT_UID);
            var_dump($structure);
    
            $headerText = imap_fetchHeader($mbox, $uid, FT_UID);
            $header = imap_rfc822_parse_headers($headerText);
    
            $body = "";
            $filename = "";
            $attachments = "";
            $messageNumber = $id;
    
            if (isset($structure->parts)) {
                var_dump($structure->subtype);
    
                switch ($structure->subtype) {
                    case 'ALTERNATIVE':
                        $body2 = imap_fetchbody($mbox, $uid, 2, FT_UID) ?? imap_fetchbody($mbox, $uid, 1.2, FT_UID);
                        $body2 = $this->decodeCharset($body2);
                        break;
    
                    case 'PLAIN':
                        $body2 = imap_fetchbody($mbox, $uid, 1, FT_UID) ?? imap_fetchbody($mbox, $uid, 1.1, FT_UID);
                        break;
    
                    case 'HTML':
                        $possibleParts = [1.1, 1.2, 1, 1.0, 1.3];
                        foreach ($possibleParts as $part) {
                            $body2 = imap_fetchbody($mbox, $uid, $part, FT_UID);
                            if ($body2 !== null) {
                                break;
                            }
                        }
                        break;
    
                    default:
                        break;
                }
    
                if ($body2 !== null) {
                    $body = quoted_printable_decode($body2);
                }
            } else {
                $body = imap_fetchbody($mbox, $uid, 1, FT_UID) ?? imap_fetchbody($mbox, $uid, 1.1, FT_UID);
                $body = quoted_printable_decode($body);
                $body = $this->detectAndDecodeCharset($body);
                var_dump($body);
            }
    
            // Handling for RELATED and MIXED subtypes
            if ($structure->subtype == 'RELATED') {
                $data = $this->handleRelatedSubtype($mbox, $uid, $structure, $assetPackage, $body);
                $body = $data['body'];
                 $attachments = $data['attachments'];
            }
    
            if ($structure->subtype == 'MIXED') {
               
                $data = $this->handleMixedSubtype($mbox, $uid, $structure, $assetPackage, $body);
                $body = $data['body'];
                $attachments = $data['attachments'];
            }
    
            imap_close($mbox);
    
            if ($this->is_base64_encoded($body) == true) {
                $body = base64_decode($body);
            }
    
            if (strpos($body, '<') !== false && strpos($body, '>') !== false) {
                $allowed_tags = '<a><abbr><acronym><address><area><article><aside><audio><b><basefont><bdo><big><blockquote><br><button><canvas><caption><center><cite><code><col><colgroup><datalist><dd><del><details><dfn><dir><div><dl><dt><em><embed><fieldset><figcaption><figure><font><footer><form><h1><h2><h3><h4><h5><h6><head><header><hr><i><iframe><img><input><ins><kbd><keygen><label><legend><li><map><menu><meter><nav><noscript><object><ol><optgroup><option><output><p><param><pre><progress><q><rp><rt><ruby><s><samp><script><section><select><small><source><span><strike><style><strong><sub><sup><table><tbody><td><textarea><tfoot><th><thead><time><title><tr><track><tt><u><ul><var><video>>';
                $body = strip_tags($body, $allowed_tags);
                $body = $this->deleteStyle($body);
            }
    
            $bodymsg = mb_convert_encoding($bodymsg, "UTF-8", $encoding);
            return $this->render('core\emails\readinbox.html.twig', [
                'header' => $header,
                'corps' => $body,
                'attachement' => $attachments,
                'structure' => $structure,
                'object' => "",
                'attachments' => $attachments,
                'id' => $messageNumber,
            ]);
        }
    }
    
    private function handleRelatedSubtype($mbox, $uid, $structure, $assetPackage, $body) {
        $attachments = []; // Array to hold attachment information
    
        if (isset($structure->parts)) {
            $parts = $structure->parts;
            $body2 = imap_fetchbody($mbox, $uid, 1.2, FT_UID) ?: imap_fetchbody($mbox, $uid, 1, FT_UID);
            $body = quoted_printable_decode($body2);
            $i = 0;
            foreach ($parts as $part) {
                if ($parts[$i]) {
                    $i++;
                    if (isset($parts[$i]) && $parts[$i]->ifid == 1) {
                        $id = substr($parts[$i]->id, 1, -1);
                        $imageid = "cid:" . $id;
                        foreach ($parts[$i]->parameters as $object) {
                            $filename = $assetPackage->getUrl("emails/inline/" . mb_decode_mimeheader($object->value));
                            $path = $this->getParameter('kernel_directory') . "/public/emails/inline/" . mb_decode_mimeheader($object->value);
                            $attachment = imap_fetchbody($mbox, $uid, ($i + 1), FT_UID);
                            if ($structure->parts[$i]->encoding == 3) {
                                $attachment = base64_decode($attachment);
                            } elseif ($structure->parts[$i]->encoding == 4) {
                                $attachment = quoted_printable_decode($attachment);
                            } else {
                                echo "encod:" . $structure->parts[$i]->encoding . PHP_EOL;
                            }
                            file_put_contents($path, $attachment);
                            
                            // Add attachment information to the $attachments array
                            $attachments[] = [
                                'filename' => mb_decode_mimeheader($object->value),
                                'path' => $path,
                                'url' => $filename,
                                'content' => $attachment
                            ];
    
                            $body = str_replace($imageid, $filename, $body);
                        }
                    }
                }
            }
        }
    
        // Return both the body and attachments
        return [
            'body' => $body,
            'attachments' => $attachments
        ];
    }
    
    private function handleMixedSubtype($mbox, $uid, $structure, $assetPackage, $body) {
        $attachments = [];
        $returnData = [];
    
        if (isset($structure->parts) && count($structure->parts)) {
            for ($e = 0; $e < count($structure->parts); $e++) {
                $attachments[$e] = ['is_attachment' => false, 'filename' => '', 'name' => '', 'attachment' => ''];
    
                if ($structure->parts[$e]->type != 1) {
                    if ($structure->parts[$e]->ifdparameters) {
                        foreach ($structure->parts[$e]->dparameters as $object) {
                            if (strtolower($object->attribute) == 'filename') {
                                $attachments[$e]['is_attachment'] = true;
                                $attachments[$e]['filename'] = iconv('UTF-8', 'ASCII//TRANSLIT//IGNORE', $this->suppraccent(mb_decode_mimeheader($object->value)));
                            }
                        }
                    }
    
                    if ($structure->parts[$e]->ifparameters) {
                        foreach ($structure->parts[$e]->parameters as $object) {
                            if (strtolower($object->attribute) == 'name') {
                                $attachments[$e]['is_attachment'] = true;
                                $attachments[$e]['name'] = iconv('UTF-8', 'ASCII//TRANSLIT//IGNORE', $this->suppraccent(mb_decode_mimeheader($object->value)));
                            }
                        }
                    }
    
                    if ($attachments[$e]['is_attachment']) {
                        $attachments[$e]['attachment'] = imap_fetchbody($mbox, $uid, ($e + 1), FT_UID);
                        if ($structure->parts[$e]->encoding == 3) {
                            $attachments[$e]['attachment'] = base64_decode($attachments[$e]['attachment']);
                        } elseif ($structure->parts[$e]->encoding == 4) {
                            $attachments[$e]['attachment'] = quoted_printable_decode($attachments[$e]['attachment']);
                        }
                        $path = $this->getParameter('kernel_directory') . "/public/emails/inline/" . $attachments[$e]['name'];
                        file_put_contents($path, $attachments[$e]['attachment']);
                    }
                }
            }
        }
    
        // Extracting and processing the body
        $bodymsg = quoted_printable_decode(imap_fetchbody($mbox, $uid, 1, FT_UID));
        if (empty($bodymsg)) {
            $bodymsg = quoted_printable_decode(imap_fetchbody($mbox, $uid, 1.1, FT_UID));
        }
    
        $crawler = new Crawler($bodymsg);
        $ltrDivs = $crawler->filter('div[dir=ltr]');
        if ($ltrDivs->count() > 0) {
            $ltrDiv = $ltrDivs->first();
            $extractedHtml = $ltrDiv->html();
            $bodymsg = $extractedHtml;
        }
    
        $bodymsg = mb_convert_encoding($bodymsg, "UTF-8", "auto");
        $body = $bodymsg;
    
        // Processing inline attachments
        $source = imap_fetchbody($mbox, $uid, 2, FT_UID);
        if (isset($structure->parts[0]->parts)) {
            $inlines = [];
            for ($j = 0; $j < count($structure->parts[0]->parts); $j++) {
                if ($structure->parts[0]->parts[$j]->type == 5) {
                    $imageId = substr($structure->parts[0]->parts[$j]->id, 1, -1);
                    $uniqueName = uniqid('img_') . "." . $structure->parts[0]->parts[$j]->subtype;
                    $partNumber = ("1." . $j + 1);
                    $inlines[$j] = ['is_inline' => true, 'name' => $uniqueName, 'filename' => iconv('UTF-8', 'ASCII//TRANSLIT//IGNORE', $this->suppraccent(mb_decode_mimeheader($structure->parts[0]->parts[$j]->parameters[0]->value))), 'attachment' => base64_decode(imap_fetchbody($mbox, $uid, $partNumber, FT_UID))];
                    $path = $this->getParameter('kernel_directory') . "/public/emails/inline/" . $uniqueName;
                    file_put_contents($path, $inlines[$j]['attachment']);
                    $imageid = "cid:" . $imageId;
                    $filename = $assetPackage->getUrl("emails/inline/" . $uniqueName);
                    $body = str_replace($imageid, $filename, $body);
                }
            }
        }
    
        // Adding body and attachments to returnData array
        $returnData['body'] = $body;
        $returnData['attachments'] = $attachments;
    
        return $returnData;
    }
    
    
    private function decodeCharset($string) {
        $encoding = mb_detect_encoding($string, mb_detect_order(), true);
        if ($encoding === "ASCII") {
         $string = mb_convert_encoding($string, "UTF-8", $encoding);
        } 
    
    
    
             elseif ($encoding === "UTF-8") {
            $string = quoted_printable_decode($string);
        }
    
    
         else {
            $string = iconv($encoding, 'UTF-8', quoted_printable_decode($string));
        }
    
    
    
    
    // Decode the string to UTF-8
    $string = mb_convert_encoding($string, "UTF-8", $encoding);
    
    
    
    
        return $string;
    }
    
    private function detectAndDecodeCharset($string) {
        $originalCharset = mb_detect_encoding($string);
        $string = mb_convert_encoding($string, 'UTF-8', $originalCharset);
        return $string;
    }
    
    
    private function is_base64_encoded($string) {
        // Remove any whitespace characters from the input string
        $string = trim($string);
        
        // Base64 encoding typically contains characters A-Z, a-z, 0-9, +, /, and sometimes =
        // Check if the decoded string is not false and if the decoded string contains only valid characters
        return base64_decode($string, true) !== false && preg_match('%^[a-zA-Z0-9/+]*={0,2}$%', $string);
    }
    
    
    
    private  function contains_html_tags($string) {
        return preg_match("/<[^<]+>/", $string) === 1;
    }
    
    private  function deleteStyle($bodymsg){
    
    
    
        $crawler = new Crawler($bodymsg);
    // Find all <style> tags and remove them
    $crawler->filter('style')->each(function (Crawler $node) {
        $node->getNode(0)->parentNode->removeChild($node->getNode(0));
    });
    
    // Get the updated HTML after removing <style> tags
    $bodymsg = $crawler->html();
    
         
           return $bodymsg;
    
    }
    



    En vous remerciant 

    Cordialement 

    • Partager sur Facebook
    • Partager sur Twitter

    Lecture des mails avec IMAP

    × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
    • Editeur
    • Markdown