Я создам PHP скрипт для работы с письмами через IMAP с подробными комментариями, который выполняет указанные требования. Код будет процедурным, с обработкой писем из папки INBOX, сохранением в SQLite и архивацией тела письма.
Этот скрипт:
- Подключается к IMAP серверу и SQLite базе данных
- Создаёт таблицу emails в SQLite, если она не существует
- Получает все письма из папки INBOX
- Для каждого письма:
- Извлекает UID, email отправителя, дату и тему
- Создаёт MD5 хэш из UID, email отправителя и даты
- Получает полное тело письма
- Извлекает имена прикреплённых файлов
- Сохраняет данные в SQLite (хэш, email отправителя, тему, тело, JSON массив имён файлов, дату и timestamp)
- Создаёт директорию attach/год/месяц/день/хэш
- Сохраняет тело письма в файл body
- Создаёт ZIP архив с телом письма, используя timestamp в имени файла
- Закрывает соединения
Для использования скрипта:
- Замените $imap_host, $imap_user, $imap_pass на ваши данные
- Убедитесь, что включены PHP расширения imap, sqlite3 и zip
- Установите права на запись для директории attach
- Создайте директорию attach в корне проекта
Скрипт обрабатывает ошибки на каждом этапе и выводит сообщения об ошибках, если они возникают.
Ошибка PHP Fatal error: Uncaught Error: Object of class stdClass could not be converted to string в строке с file_put_contents($body_file, $raw_body) указывает на то, что переменная $raw_body содержит объект stdClass вместо строки, а функция file_put_contents ожидает строку в качестве второго аргумента.
Причина ошибки
В вашем коде строка $raw_body = imap_fetchbody($imap, $email_number, ''); должна возвращать тело письма в виде строки, но, вероятно, из-за некорректной работы функции imap_fetchbody или особенностей структуры письма, возвращается объект или неверный тип данных. Это может произойти, если:
- Письмо имеет сложную структуру (например, multipart), и imap_fetchbody возвращает неожиданные данные.
- Вы используете пустую секцию ('') в imap_fetchbody, что может не всегда корректно работать для получения полного тела письма.
- Возможно, вы случайно изменили значение $raw_body где-то в коде до вызова file_put_contents.
Решение
Чтобы исправить ошибку, нужно:
- Убедиться, что $raw_body всегда содержит строку.
- Использовать более надёжный способ получения полного тела письма.
- Добавить проверку типа данных и обработку ошибок.
Исправленный фрагмент кода
Ниже приведён исправленный фрагмент кода для обработки тела письма с подробными комментариями:
// Получение полного тела письма (включая все части)
$raw_body = imap_fetchbody($imap, $email_number, 0); // Используем секцию 0 для полного тела
if ($raw_body === false || $raw_body === null) {
echo "Не удалось получить тело письма №$email_number: " . imap_last_error() . "\n";
continue;
}
// Проверка типа данных $raw_body
if (!is_string($raw_body)) {
echo "Тело письма №$email_number не является строкой, тип: " . gettype($raw_body) . "\n";
continue;
}
// Декодирование тела письма, если оно закодировано
$structure = imap_fetchstructure($imap, $email_number);
if ($structure && isset($structure->encoding)) {
switch ($structure->encoding) {
case 3: // base64
$raw_body = base64_decode($raw_body);
break;
case 4: // quoted-printable
$raw_body = quoted_printable_decode($raw_body);
break;
default:
// Другие типы кодирования (0 - 7bit, 1 - 8bit, 2 - binary) обычно не требуют декодирования
break;
}
}
// Повторная проверка, что $raw_body — строка после декодирования
if (!is_string($raw_body)) {
echo "После декодирования тело письма №$email_number не является строкой\n";
continue;
}
// Сохранение тела письма в файл
$body_file = "$save_path/body";
if (file_put_contents($body_file, $raw_body) === false) {
echo "Ошибка при сохранении тела письма №$email_number\n";
continue;
}Что изменено:
- Использование секции 0: Вместо пустой строки ('') в imap_fetchbody используется секция 0, которая обычно возвращает полное тело письма, включая заголовки и все части.
- Проверка возвращаемого значения: Добавлена проверка на false или null для обработки ошибок imap_fetchbody.
- Проверка типа данных: Перед сохранением проверяется, что $raw_body — строка, с выводом типа данных в случае ошибки для диагностики.
- Декодирование тела письма: Если письмо закодировано (например, base64 или quoted-printable), оно декодируется в строку.
- Повторная проверка после декодирования: Убедимся, что после декодирования $raw_body всё ещё строка.
Дополнительные рекомендации
- Логирование для отладки:
Добавьте логирование в файл, чтобы отслеживать, какие письма вызывают проблемы:
phpfile_put_contents('email_errors.log', "Письмо №$email_number, тип raw_body: " . gettype($raw_body) . "\n", FILE_APPEND);
- Обработка сложных писем:
Если письма имеют сложную структуру (multipart), используйте функцию imap_fetchstructure для рекурсивной обработки всех частей:
phpfunction get_email_body($imap, $email_number, $section = '') {$body = '';$structure = imap_fetchstructure($imap, $email_number);if (isset($structure->parts) && is_array($structure->parts)) {foreach ($structure->parts as $part_num => $part) {$body .= imap_fetchbody($imap, $email_number, $section . ($part_num + 1));}} else {$body = imap_fetchbody($imap, $email_number, $section ?: 1);}return $body;}$raw_body = get_email_body($imap, $email_number);
- Проверка прав доступа: Убедитесь, что у
Я создам PHP скрипт, который разархивирует созданный ранее ZIP-архив с телом письма, читает файл body и полностью анализирует его структуру, учитывая различные кодировки (base64, quoted-printable, 7bit, 8bit и другие). Код будет процедурным, с подробными комментариями, и будет работать с файлами, созданными в предыдущем скрипте (в директории attach/год/месяц/день/хэш). Скрипт также обработает возможные кодировки текста письма и извлечёт содержимое, включая заголовки, текстовые части и прикреплённые файлы.
Объяснение кода
- Разархивация ZIP:
- Открывается ZIP-архив, созданный ранее, по пути attach/год/месяц/день/хэш/timestamp.zip.
- Содержимое извлекается в временную директорию extracted.
- Проверяется существование файла body после разархивации.
- Чтение файла body:
- Файл читается с помощью file_get_contents.
- Проверяется успешность чтения.
- Обработка кодировок:
- Функция decode_body обрабатывает различные типы кодировок (base64, quoted-printable, 7bit, 8bit, binary).
- Функция convert_charset конвертирует текстовые части в UTF-8, если указана другая кодировка (например, ISO-8859-1).
- Анализ структуры письма:
- Письмо разделяется на заголовки и тело по двойному переводу строки (\r\n\r\n).
- Заголовки парсятся в ассоциативный массив.
- Если доступно IMAP-соединение, используется imap_fetchstructure для получения структуры письма (multipart, text, attachments).
- Функция parse_part рекурсивно обрабатывает все части письма:
- Текстовые части (text/plain, text/html) декодируются и сохраняются.
- Вложения извлекаются с именами файлов и размером.
- Поддерживаются вложенные multipart-структуры.
- Вывод результата:
- Выводится структура письма: заголовки, текстовые части, HTML-части и вложения.
- Очистка:
- Удаляется временный файл body и директория extracted.
Использование
- Замените $cache_hash и $timestamp на реальные значения из вашей базы данных SQLite (например, из таблицы emails).
- Укажите правильные данные для IMAP-соединения ($imap_host, $imap_user, $imap_pass).
- Укажите номер письма ($email_number), если IMAP-соединение активно. Если IMAP недоступен, скрипт всё равно обработает тело письма как текст.
- Убедитесь, что PHP расширения zip, imap и mbstring включены.
- Проверьте права на запись/чтение в директории attach.
Примечания
- Если IMAP-соединение недоступно, скрипт всё равно парсит заголовки и тело письма, предполагая, что это текст.
- Для сложных писем (например, с вложенными multipart-структурами) рекомендуется использовать IMAP-соединение для точного анализа.
- Для диагностики можно добавить логирование:
phpfile_put_contents('parse_log.txt', print_r($parsed_email, true), FILE_APPEND);
- Если кодировка не распознана, используется UTF-8 по умолчанию.
Пример вывода
Структура письма:
Заголовки:
Array
(
[From] => sender@example.com
[Subject] => Test Email
[Content-Type] => multipart/mixed; charset=UTF-8
)
Текстовые части:
Array
(
[0] => Это текстовое содержимое письма.
)
HTML части:
Array
(
[0] => <p>Это HTML содержимое письма.</p>
)
Вложения:
Array
(
[0] => Array
(
[filename] => document.pdf
[size] => 123456
)
)
Обработка завершена.Этот скрипт полностью соответствует требованиям и учитывает все возможные кодировки, обеспечивая надёжный анализ структуры письма.
Я создам HTML-интерфейс с использованием PHP и JavaScript для отображения структуры папок на сервере, просмотра содержимого папок, парсинга файлов .eml и отображения их содержимого как в почтовом клиенте. Код будет включать рекурсивное сканирование директорий, обработку кодировок, парсинг заголовков и тела писем, а также возможность загрузки архивов (ZIP, содержащих .eml) или отдельных .eml файлов для парсинга.
Объяснение кода
HTML и JavaScript (Frontend)
- Интерфейс:
- Два блока: слева — дерево папок, справа — список файлов и содержимое письма.
- Секция загрузки файлов позволяет выбрать .eml или .zip файлы.
- CSS стили для удобного отображения структуры и содержимого.
- JavaScript:
- loadFolderTree: Запрашивает структуру папок через AJAX (?action=get_folder_tree) и рендерит дерево.
- renderTree: Рекурсивно строит HTML-список папок.
- loadFiles: Загружает файлы в выбранной папке через AJAX (?action=get_files).
- openFile: Для .eml файлов запрашивает парсинг (?action=parse_eml), для других — скачивание.
- uploadFile: Отправляет файл на сервер через AJAX (?action=upload_file).
- getHeaderDescription: Возвращает описание служебных заголовков.
- Отображение письма:
- Показывает отправителя, получателя, тему, дату, все заголовки с описаниями, текстовые и HTML части, а также вложения.
PHP (Backend)
- Обработка запросов:
- get_folder_tree: Рекурсивно сканирует директорию attach и возвращает JSON с деревом папок.
- get_files: Возвращает список файлов в указанной папке.
- parse_eml: Парсит .eml файл, извлекая заголовки, текст, HTML и вложения.
- download: Отдаёт файл для скачивания.
- upload_file: Принимает .eml или .zip, сохраняет в attach/uploads, разархивирует ZIP если нужно.
- Парсинг EML:
- parse_eml_file: Читает .eml файл, разделяет на заголовки и тело.
- parse_eml_body: Рекурсивно парсит тело, обрабатывая multipart-структуры, кодировки (base64, quoted-printable) и конвертируя текст в UTF-8.
- parse_sub_headers: Парсит заголовки для частей письма (например, Content-Type, Content-Disposition).
- Обработка кодировок:
- Извлекается кодировка из Content-Type (по умолчанию UTF-8).
- Заголовки декодируются с помощью mb_decode_mimeheader.
- Тело декодируется (base64, quoted-printable) и конвертируется в UTF-8 с помощью mb_convert_encoding.
Использование
- Размещение:
- Разместите файл file_explorer.php в корне веб-сервера.
- Убедитесь, что директория attach существует и доступна для чтения/записи.
- Убедитесь, что включены PHP расширения mbstring и zip.
- Настройка:
- Измените $base_dir = 'attach' на нужную директорию, если требуется.
- Убедитесь, что веб-сервер имеет права на запись в attach/uploads.
- Запуск:
- Откройте file_explorer.php в браузере.
- Проводник отобразит структуру папок в attach.
- Клик по папке покажет её файлы.
- Клик по .eml файлу отобразит содержимое письма (заголовки, текст, HTML, вложения).
- Другие файлы можно скачать.
- Загрузите .eml или .zip через форму загрузки.
Пример структуры директорий
attach/
├── 2025/
│ ├── 07/
│ │ ├── 08/
│ │ │ ├── cache_hash1/
│ │ │ │ ├── body
│ │ │ │ ├── 1625097600.zip
│ │ │ ├── cache_hash2/
│ │ │ │ ├── body
│ │ │ │ ├── 1625097610.zip
├── uploads/
│ ├── uploaded_file.eml
│ ├── extracted_eml1.emlПримечания
- Кодировки: Поддерживаются base64, quoted-printable, 7bit, 8bit; текст конвертируется в UTF-8.
- Безопасность: Для продакшена добавьте проверку типов файлов и размеров при загрузке.
- Логирование: Для отладки можно добавить логи в файл:
phpfile_put_contents('parse_log.txt', print_r($result, true), FILE_APPEND);
- Ограничения: Если .eml файл имеет сложную структуру, убедитесь, что все boundary корректно парсятся.
Этот интерфейс полностью соответствует требованиям, обеспечивая удобный просмотр структуры папок и содержимого писем с учётом всех кодировок.