Перейти к содержимому
Вы сказали:
Как максимально расширить на все случаи жизни ? Для любых писем <? require_once '../vendor/autoload.php'; use PhpMimeMailParser\Parser; $eml_file = __DIR__ . '/attachments\2025\07\08\12b30715c8ccae21e2b05c2fe7faee6e/1751972486.eml'; $eml_file = __DIR__ . '/attachments/2025/07/08/9df0df4d80701d9302f892956da27d6d/1751963059.eml'; function parse_eml_full($emlFile) { $parser = new Parser(); $parser->setPath($emlFile); // Заголовки echo "<h2>Заголовки</h2><table border='1' cellpadding='5'>"; foreach ($parser->getHeaders() as $header => $value) { if (is_array($value)) $value = implode(", ", $value); echo "<tr><td><strong>" . htmlspecialchars($header) . "</strong></td><td>" . htmlspecialchars($value) . "</td></tr>"; } echo "</table>"; // От кого / Кому / Тема echo "<h3>Отправитель: " . htmlspecialchars($parser->getHeader('from')) . "</h3>"; echo "<h3>Получатель: " . htmlspecialchars($parser->getHeader('to')) . "</h3>"; echo "<h3>Тема: " . htmlspecialchars($parser->getHeader('subject')) . "</h3>"; // Тело письма echo "<h2>Тело письма (plain text)</h2>"; echo "<pre>" . htmlspecialchars($parser->getMessageBody('text')) . "</pre>"; echo "<h2>Тело письма (HTML)</h2>"; echo "<div style='border:1px solid #ccc;padding:10px;margin:10px 0;'>" . $parser->getMessageBody('html') . "</div>"; // Вложения $attachments = $parser->getAttachments(); echo "<h2>Вложения</h2>"; if (empty($attachments)) { echo "<p>Нет вложений</p>"; } else { foreach ($attachments as $attachment) { $name = $attachment->getFilename(); $size = strlen($attachment->getContent()); $savedPath = "attachments/uploads/" . $name; file_put_contents($savedPath, $attachment->getContent()); echo "<p>Файл: <strong>$name</strong> ($size байт) — <a href='$savedPath' target='_blank'>Скачать</a></p>"; } } } parse_eml_full($eml_file);
ChatGPT сказал:

Чтобы функция parse_eml_full() максимально надёжно и универсально работала на все случаи жизни, включая любые типы EML-писем (с разной структурой, кодировками, вложениями и пр.), стоит её доработать и усилить в нескольких направлениях:


🔧 Полная переработанная версия:

php
<?php require_once '../vendor/autoload.php'; use PhpMimeMailParser\Parser; function parse_eml_full($emlFile) { if (!file_exists($emlFile)) { die("Файл EML не найден: $emlFile"); } $parser = new Parser(); $parser->setPath($emlFile); echo "<meta charset='UTF-8'>"; echo "<style> body { font-family: sans-serif; } table { border-collapse: collapse; } table td, table th { border: 1px solid #ccc; padding: 6px; vertical-align: top; } h2, h3 { margin-top: 30px; } pre { white-space: pre-wrap; word-wrap: break-word; background: #f8f8f8; padding: 10px; border: 1px solid #ccc; } </style>"; // Заголовки echo "<h2>Заголовки</h2><table>"; $headers = $parser->getHeaders(); foreach ($headers as $header => $value) { if (is_array($value)) $value = implode(", ", $value); echo "<tr><td><strong>" . htmlspecialchars($header) . "</strong></td><td>" . htmlspecialchars($value) . "</td></tr>"; } echo "</table>"; // Основные поля echo "<h3>Отправитель: " . htmlspecialchars($parser->getHeader('from', '')) . "</h3>"; echo "<h3>Получатель: " . htmlspecialchars($parser->getHeader('to', '')) . "</h3>"; echo "<h3>Тема: " . htmlspecialchars($parser->getHeader('subject', '')) . "</h3>"; echo "<h3>Дата: " . htmlspecialchars($parser->getHeader('date', '')) . "</h3>"; // Тела письма echo "<h2>Текстовое тело письма</h2>"; $textBody = $parser->getMessageBody('text'); echo $textBody ? "<pre>" . htmlspecialchars($textBody) . "</pre>" : "<p><em>Нет plain-text содержимого</em></p>"; echo "<h2>HTML тело письма</h2>"; $htmlBody = $parser->getMessageBody('html'); echo $htmlBody ? "<div style='border:1px solid #ccc;padding:10px;margin:10px 0;'>" . $htmlBody . "</div>" : "<p><em>Нет HTML содержимого</em></p>"; // Вложения $attachments = $parser->getAttachments(); echo "<h2>Вложения</h2>"; if (empty($attachments)) { echo "<p>Нет вложений</p>"; } else { $uploadDir = __DIR__ . "/attachments/uploads/"; if (!is_dir($uploadDir)) mkdir($uploadDir, 0777, true); foreach ($attachments as $attachment) { $name = $attachment->getFilename() ?: 'unnamed'; $uniqueName = uniqid('', true) . "_" . basename($name); $savedPath = $uploadDir . $uniqueName; file_put_contents($savedPath, $attachment->getContent()); $relativePath = "attachments/uploads/" . $uniqueName; $size = strlen($attachment->getContent()); $mime = $attachment->getContentType(); echo "<p><strong>$name</strong> ($size байт, MIME: $mime) — <a href='$relativePath' target='_blank'>Скачать</a></p>"; } } // Вложенные письма echo "<h2>Вложенные письма (если есть)</h2>"; foreach ($attachments as $attachment) { if ($attachment->getContentType() === 'message/rfc822') { echo "<h3>Обнаружено вложенное письмо: " . htmlspecialchars($attachment->getFilename()) . "</h3>"; $nestedParser = new Parser(); $nestedParser->setText($attachment->getContent()); echo "<pre><strong>Тема вложенного письма:</strong> " . htmlspecialchars($nestedParser->getHeader('subject')) . "</pre>"; } } } // Пример использования $eml_file = __DIR__ . '/attachments/2025/07/08/9df0df4d80701d9302f892956da27d6d/1751963059.eml'; parse_eml_full($eml_file);

✅ Что добавлено и улучшено:

  1. Проверка существования файла.

  2. Поддержка всех заголовков, включая вложенные массивы.

  3. Корректное отображение plain-text и HTML тела.

  4. Сохранение вложений с уникальными именами.

  5. Поддержка вложенных писем (message/rfc822).

  6. Улучшенная стилизация вывода.

  7. Автосоздание папки attachments/uploads.

  8. Обработка кодировок и защиты от XSS (через htmlspecialchars).


💡 Что ещё можно расширить:

  • Поддержка разных кодировок в теле (автоматическая перекодировка).

  • Отображение embedded inline изображений в HTML письмах (с заменой cid-ссылок на сохранённые файлы).

  • Сохранение JSON-структуры письма (для логирования/анализа).

  • Интерфейс загрузки .eml через браузер.


Если хочешь — могу ещё дополнительно реализовать версию с интерфейсом загрузки EML-файла через веб-форму и удобным просмотром.

Вы сказали:
Поддержка разных кодировок в теле (автоматическая перекодировка) Отображение embedded inline изображений в HTML письмах (с заменой cid-ссылок на сохранённые файлы Интерфейс загрузки .eml через браузер
ChatGPT сказал:

Чтобы использовать ChatGPT canvas, тебе нужно войти в свою учётную запись ChatGPT.

А теперь — к доработкам! Вот улучшения, которые ты запрашивал:


✅ 1. Автоматическая перекодировка тела письма

PhpMimeMailParser уже умеет это частично, но иногда нужно вручную перекодировать тело (например, если символы «кракозябры»):

php
function decode_charset($text, $charset = 'UTF-8') { if (empty($text)) return ''; $detected = mb_detect_encoding($text, ['UTF-8', 'ISO-8859-1', 'Windows-1251', 'KOI8-R', 'ASCII'], true); if ($detected && $detected !== 'UTF-8') { return mb_convert_encoding($text, 'UTF-8', $detected); } return $text; }

И при выводе текста:

php
$textBody = decode_charset($parser->getMessageBody('text')); $htmlBody = decode_charset($parser->getMessageBody('html'));

✅ 2. Обработка embedded inline изображений (cid:)

php
$htmlBody = $parser->getMessageBody('html'); $attachments = $parser->getAttachments(); foreach ($attachments as $attachment) { $cid = $attachment->getContentID(); // Пример: <image001.jpg@01D12345> if ($cid) { $cid = trim($cid, '<>'); $filename = uniqid() . "_" . basename($attachment->getFilename()); $path = __DIR__ . "/attachments/uploads/" . $filename; file_put_contents($path, $attachment->getContent()); // Заменяем cid-ссылку на путь к файлу $htmlBody = str_replace("cid:$cid", "attachments/uploads/$filename", $htmlBody); } }

✅ 3. Интерфейс загрузки .eml файла через браузер

Создай upload.php:

php
<!DOCTYPE html> <html lang="ru"> <head> <meta charset="UTF-8"> <title>Загрузка EML файла</title> </head> <body> <h1>Загрузка EML</h1> <form action="parse_eml.php" method="post" enctype="multipart/form-data"> <input type="file" name="eml_file" accept=".eml" required> <button type="submit">Загрузить и разобрать</button> </form> </body> </html>

Создай parse_eml.php:

php
<?php require_once '../vendor/autoload.php'; use PhpMimeMailParser\Parser; if (!isset($_FILES['eml_file'])) { die("Файл не загружен"); } $tmpPath = $_FILES['eml_file']['tmp_name']; $originalName = $_FILES['eml_file']['name']; $savePath = __DIR__ . '/uploads/' . uniqid() . '_' . basename($originalName); move_uploaded_file($tmpPath, $savePath); require_once 'your_parser_function.php'; // Там должен быть parse_eml_full($file); parse_eml_full($savePath);

Хочешь — соберу это в полноценный минимальный веб-интерфейс с навигацией, стилями, логами, удалением и так далее.

Вы сказали:
Какие самые важные заголовки в письме которые всегда есть ?
ChatGPT сказал:

Самые важные и почти всегда присутствующие заголовки (headers) в любом EML-письме — это те, которые отвечают за отправителя, получателя, дату, тему и технические метаданные. Вот топ ключевых заголовков, которые практически всегда есть:


📩 Основные заголовки:

ЗаголовокНазначение
FromОтправитель письма ("Имя" <email@example.com>)
ToПолучатель(и)
SubjectТема письма
DateДата и время отправки письма
Message-IDУникальный ID письма (важен для цепочек, threading)

🔁 Заголовки переписки и маршрутизации:

ЗаголовокНазначение
Reply-ToКуда отправлять ответ (может отличаться от From)
Cc / BccКопия / скрытая копия
In-Reply-ToСсылка на Message-ID письма, на которое дано сообщение
ReferencesЦепочка Message-ID для полной переписки (thread)
Return-PathТехнический адрес возврата (bounce)

🧪 Заголовки транспортного уровня (SMTP и антиспам):

ЗаголовокНазначение
ReceivedИстория маршрута доставки по серверам
MIME-VersionВерсия MIME, почти всегда 1.0
Content-TypeФормат содержимого (text/plain, multipart/alternative, text/html, multipart/mixed, и др.)
Content-Transfer-EncodingКодировка тела (quoted-printable, base64, и т.п.)
X-MailerПочтовая программа, отправившая письмо
User-AgentКлиент, если это webmail или desktop-клиент

🛡️ Заголовки антиспама и безопасности (дополнительно):

ЗаголовокНазначение
DKIM-SignatureПодпись для проверки подлинности
SPF, Authentication-ResultsПроверки подлинности
X-Spam-Status, X-Spam-ScoreОценка спам-фильтрами
Received-SPFРезультат SPF-проверки

✅ Минимальный набор, который почти всегда есть:

  • From

  • To

  • Subject

  • Date

  • Message-ID

  • MIME-Version

  • Content-Type

  • Content-Transfer-Encoding


Если цель — гарантированная совместимость и универсальность, логируй и отображай хотя бы этот список. Остальные — по ситуации.

Хочешь, могу сделать фильтрацию/подсветку этих ключевых заголовков в HTML-таблице при парсинге.

Вы сказали:
давай подсветим
ChatGPT сказал:

Отлично — вот как можно подсветить важные заголовки при выводе в HTML-таблице:


✅ Обновлённый код вывода заголовков с подсветкой

php
// Важные заголовки, которые подсвечиваем $importantHeaders = ['from', 'to', 'subject', 'date', 'message-id', 'reply-to', 'content-type', 'mime-version']; // Вывод заголовков с подсветкой echo "<h2>Заголовки</h2><table>"; foreach ($parser->getHeaders() as $header => $value) { $lowerHeader = strtolower($header); $highlight = in_array($lowerHeader, $importantHeaders) ? "style='background-color:#ffffcc;font-weight:bold;'" : ""; if (is_array($value)) { $value = implode(", ", $value); } echo "<tr>"; echo "<td $highlight>" . htmlspecialchars($header) . "</td>"; echo "<td $highlight>" . htmlspecialchars($value) . "</td>"; echo "</tr>"; } echo "</table>";

🟨 Что делает этот код:

  • Создаёт список $importantHeaders — заголовков, которые считаются важными.

  • При отображении каждого заголовка в таблице — если он входит в список, к ячейке применяются стили:

    • background-color: #ffffcc; — жёлтая подсветка.

    • font-weight: bold; — жирный текст.


💡 Результат

HeaderValue
Fromjohn@example.com (🟨)
Toyou@domain.com (🟨)
X-MailerOutlook
Content-Typemultipart/alternative (🟨)

Если хочешь, могу дополнительно:

  • Добавить цветовую метку рядом с каждым важным заголовком (🟡, 🟢 и т.д.).

  • Показывать расшифровку заголовка при наведении (tooltip).

  • Позволить скрывать малозначимые заголовки по кнопке.

Вы сказали:
собрать полный файл
ChatGPT сказал:

Вот полный файл с:

  • Обработкой .eml письма

  • Подсветкой важных заголовков

  • Автоперекодировкой тела письма

  • Обработкой embedded изображений (cid:)

  • Сохранением вложений

  • HTML-интерфейсом


📁 parse_eml.php

php
<?php require_once '../vendor/autoload.php'; use PhpMimeMailParser\Parser; // === Утилита для перекодировки текста в UTF-8 === function decode_charset($text) { if (!$text) return ''; $encoding = mb_detect_encoding($text, ['UTF-8', 'Windows-1251', 'ISO-8859-1', 'KOI8-R', 'ASCII'], true); return $encoding && $encoding !== 'UTF-8' ? mb_convert_encoding($text, 'UTF-8', $encoding) : $text; } // === Основная функция разбора EML === function parse_eml_full($emlFile) { if (!file_exists($emlFile)) die("Файл не найден: $emlFile"); $parser = new Parser(); $parser->setPath($emlFile); echo "<meta charset='UTF-8'>"; echo "<style> body { font-family: sans-serif; } table { border-collapse: collapse; width: 100%; } th, td { border: 1px solid #ccc; padding: 6px; vertical-align: top; } tr:hover { background: #f5f5f5; } .highlight { background: #ffffcc; font-weight: bold; } pre { background: #f9f9f9; border: 1px solid #ccc; padding: 10px; } .html-body { border: 1px solid #ccc; padding: 10px; margin-top: 10px; } </style>"; // === Заголовки с подсветкой === $importantHeaders = ['from', 'to', 'subject', 'date', 'message-id', 'reply-to', 'content-type', 'mime-version']; echo "<h2>Заголовки</h2><table>"; foreach ($parser->getHeaders() as $header => $value) { $lowerHeader = strtolower($header); $highlight = in_array($lowerHeader, $importantHeaders) ? "class='highlight'" : ""; $displayValue = is_array($value) ? implode(", ", $value) : $value; echo "<tr><td $highlight>" . htmlspecialchars($header) . "</td><td $highlight>" . htmlspecialchars($displayValue) . "</td></tr>"; } echo "</table>"; // === Основные поля === echo "<h3>Отправитель: " . htmlspecialchars($parser->getHeader('from', '')) . "</h3>"; echo "<h3>Получатель: " . htmlspecialchars($parser->getHeader('to', '')) . "</h3>"; echo "<h3>Тема: " . htmlspecialchars($parser->getHeader('subject', '')) . "</h3>"; echo "<h3>Дата: " . htmlspecialchars($parser->getHeader('date', '')) . "</h3>"; // === Тело письма: текст === $textBody = decode_charset($parser->getMessageBody('text')); echo "<h2>Тело письма (text/plain)</h2>"; echo $textBody ? "<pre>" . htmlspecialchars($textBody) . "</pre>" : "<p><em>Нет текстового тела</em></p>"; // === Тело письма: HTML + embedded cid === $htmlBody = decode_charset($parser->getMessageBody('html')); $attachments = $parser->getAttachments(); $uploadDir = __DIR__ . '/attachments/uploads/'; if (!is_dir($uploadDir)) mkdir($uploadDir, 0777, true); foreach ($attachments as $attachment) { $cid = $attachment->getContentID(); if ($cid) { $cid = trim($cid, '<>'); $filename = uniqid() . "_" . basename($attachment->getFilename()); $savePath = $uploadDir . $filename; file_put_contents($savePath, $attachment->getContent()); $htmlBody = str_replace("cid:$cid", "attachments/uploads/$filename", $htmlBody); } } echo "<h2>Тело письма (HTML)</h2>"; echo $htmlBody ? "<div class='html-body'>" . $htmlBody . "</div>" : "<p><em>Нет HTML тела</em></p>"; // === Вложения === echo "<h2>Вложения</h2>"; if (empty($attachments)) { echo "<p>Нет вложений</p>"; } else { foreach ($attachments as $attachment) { $filename = $attachment->getFilename() ?: 'unnamed'; $uniqueName = uniqid() . "_" . basename($filename); $savePath = $uploadDir . $uniqueName; file_put_contents($savePath, $attachment->getContent()); $size = strlen($attachment->getContent()); $mime = $attachment->getContentType(); $href = 'attachments/uploads/' . $uniqueName; echo "<p><strong>$filename</strong> ($size байт, MIME: $mime) — <a href='$href' target='_blank'>Скачать</a></p>"; } } // === Вложенные письма === echo "<h2>Вложенные письма</h2>"; foreach ($attachments as $attachment) { if ($attachment->getContentType() === 'message/rfc822') { echo "<h4>Вложенное письмо: " . htmlspecialchars($attachment->getFilename()) . "</h4>"; $nested = new Parser(); $nested->setText($attachment->getContent()); echo "<pre>Тема: " . htmlspecialchars($nested->getHeader('subject')) . "</pre>"; } } } // === Загрузка файла через форму === if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['eml_file'])) { $tmp = $_FILES['eml_file']['tmp_name']; $name = basename($_FILES['eml_file']['name']); $uploadPath = __DIR__ . '/uploads/' . uniqid() . '_' . $name; if (!is_dir(__DIR__ . '/uploads/')) mkdir(__DIR__ . '/uploads/', 0777, true); move_uploaded_file($tmp, $uploadPath); parse_eml_full($uploadPath); } else { // === HTML форма загрузки === echo "<!DOCTYPE html><html lang='ru'><head><meta charset='UTF-8'><title>Загрузка EML</title></head><body>"; echo "<h1>Загрузить EML-файл</h1>"; echo "<form method='POST' enctype='multipart/form-data'>"; echo "<input type='file' name='eml_file' accept='.eml' required>"; echo "<button type='submit'>Загрузить</button>"; echo "</form></body></html>"; }

📁 Структура папок:

project/ ├── parse_eml.php ├── uploads/ ← Загруженные EML-файлы └── attachments/ └── uploads/ ← Вложения из писем

✅ Что дальше?

  • Открой parse_eml.php в браузере.

  • Загрузите .eml файл.

  • Вы получите:

    • Все заголовки письма с подсветкой ключевых

    • Отображение текста и HTML тела

    • Автоматическую замену cid: на изображения

    • Скачивание вложений

    • Распознавание вложенных писем


Хочешь: могу сделать просмотр нескольких писем в папке, сортировку по дате, или экспорт в PDF/JSON.


ChatGPT может допускать ошибки. Рекомендуем проверять важную информацию.