PHP реализации сохранения письма через IMAP Расписывать код очень подробно писать процедурный код Получаем полностью все письма из INBOX Получаем полное тело письма полностью как оно приходит с сервера почтового Сохранение тела письма происходит в два этапа 1 Читаем тело письма находим UID, ПОЧТОВЫЙ ЯЩИК ОТПРАВИТЕЛЯ, И ДАТУ ПИСЬМА И создаём из этого через md5 кэш письма который дальше будем использовать Дальше сохраняем это в базе данных sqlite кэш письма, почтовый ящик, дату письма, тема письма, сообщение письма, и если есть прикрепленные документы только имена всех файлов что прикреплены сохранить массивом в json А так же дату письма как временную метку timestamp 2 Этапа сохраняем файл тела письма по пути attach/год/месяц/день/папка кэш письма/body и заархивировать тело письма в архив с именем файла timestamp даты письма

Я создам PHP скрипт для работы с письмами через IMAP с подробными комментариями, который выполняет указанные требования. Код будет процедурным, с обработкой писем из папки INBOX, сохранением в SQLite и архивацией тела письма.

imap_email_processor.php
php

Этот скрипт:

  1. Подключается к IMAP серверу и SQLite базе данных
  2. Создаёт таблицу emails в SQLite, если она не существует
  3. Получает все письма из папки INBOX
  4. Для каждого письма:
    • Извлекает UID, email отправителя, дату и тему
    • Создаёт MD5 хэш из UID, email отправителя и даты
    • Получает полное тело письма
    • Извлекает имена прикреплённых файлов
    • Сохраняет данные в SQLite (хэш, email отправителя, тему, тело, JSON массив имён файлов, дату и timestamp)
    • Создаёт директорию attach/год/месяц/день/хэш
    • Сохраняет тело письма в файл body
    • Создаёт ZIP архив с телом письма, используя timestamp в имени файла
  5. Закрывает соединения

Для использования скрипта:

  1. Замените $imap_host, $imap_user, $imap_pass на ваши данные
  2. Убедитесь, что включены PHP расширения imap, sqlite3 и zip
  3. Установите права на запись для директории attach
  4. Создайте директорию attach в корне проекта

Скрипт обрабатывает ошибки на каждом этапе и выводит сообщения об ошибках, если они возникают.

7,2s
Stack trace:... #0 file_put_contents() #1... #2 {main} thrown ... PHP Fatal error: Uncaught Error: Object of class stdClass could not be converted to string .... Stack trace: В строке if (file_put_contents($body_file, $raw_body) === false) {

Ошибка 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.

Решение

Чтобы исправить ошибку, нужно:

  1. Убедиться, что $raw_body всегда содержит строку.
  2. Использовать более надёжный способ получения полного тела письма.
  3. Добавить проверку типа данных и обработку ошибок.

Исправленный фрагмент кода

Ниже приведён исправленный фрагмент кода для обработки тела письма с подробными комментариями:

php
// Получение полного тела письма (включая все части)
$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;
}

Что изменено:

  1. Использование секции 0: Вместо пустой строки ('') в imap_fetchbody используется секция 0, которая обычно возвращает полное тело письма, включая заголовки и все части.
  2. Проверка возвращаемого значения: Добавлена проверка на false или null для обработки ошибок imap_fetchbody.
  3. Проверка типа данных: Перед сохранением проверяется, что $raw_body — строка, с выводом типа данных в случае ошибки для диагностики.
  4. Декодирование тела письма: Если письмо закодировано (например, base64 или quoted-printable), оно декодируется в строку.
  5. Повторная проверка после декодирования: Убедимся, что после декодирования $raw_body всё ещё строка.

Дополнительные рекомендации

  1. Логирование для отладки: Добавьте логирование в файл, чтобы отслеживать, какие письма вызывают проблемы:
    php
    file_put_contents('email_errors.log', "Письмо №$email_number, тип raw_body: " . gettype($raw_body) . "\n", FILE_APPEND);
  2. Обработка сложных писем: Если письма имеют сложную структуру (multipart), используйте функцию imap_fetchstructure для рекурсивной обработки всех частей:
    php
    function 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);
  3. Проверка прав доступа: Убедитесь, что у
2,1s
Прервано
Разархивировать созданный архив и прочитать полностью структуру body письма Учитывая кодировку разную на все случаи жизни

Я создам PHP скрипт, который разархивирует созданный ранее ZIP-архив с телом письма, читает файл body и полностью анализирует его структуру, учитывая различные кодировки (base64, quoted-printable, 7bit, 8bit и другие). Код будет процедурным, с подробными комментариями, и будет работать с файлами, созданными в предыдущем скрипте (в директории attach/год/месяц/день/хэш). Скрипт также обработает возможные кодировки текста письма и извлечёт содержимое, включая заголовки, текстовые части и прикреплённые файлы.

unzip_and_parse_email_body.php
php

Объяснение кода

  1. Разархивация ZIP:
    • Открывается ZIP-архив, созданный ранее, по пути attach/год/месяц/день/хэш/timestamp.zip.
    • Содержимое извлекается в временную директорию extracted.
    • Проверяется существование файла body после разархивации.
  2. Чтение файла body:
    • Файл читается с помощью file_get_contents.
    • Проверяется успешность чтения.
  3. Обработка кодировок:
    • Функция decode_body обрабатывает различные типы кодировок (base64, quoted-printable, 7bit, 8bit, binary).
    • Функция convert_charset конвертирует текстовые части в UTF-8, если указана другая кодировка (например, ISO-8859-1).
  4. Анализ структуры письма:
    • Письмо разделяется на заголовки и тело по двойному переводу строки (\r\n\r\n).
    • Заголовки парсятся в ассоциативный массив.
    • Если доступно IMAP-соединение, используется imap_fetchstructure для получения структуры письма (multipart, text, attachments).
    • Функция parse_part рекурсивно обрабатывает все части письма:
      • Текстовые части (text/plain, text/html) декодируются и сохраняются.
      • Вложения извлекаются с именами файлов и размером.
      • Поддерживаются вложенные multipart-структуры.
  5. Вывод результата:
    • Выводится структура письма: заголовки, текстовые части, HTML-части и вложения.
  6. Очистка:
    • Удаляется временный файл body и директория extracted.

Использование

  1. Замените $cache_hash и $timestamp на реальные значения из вашей базы данных SQLite (например, из таблицы emails).
  2. Укажите правильные данные для IMAP-соединения ($imap_host, $imap_user, $imap_pass).
  3. Укажите номер письма ($email_number), если IMAP-соединение активно. Если IMAP недоступен, скрипт всё равно обработает тело письма как текст.
  4. Убедитесь, что PHP расширения zip, imap и mbstring включены.
  5. Проверьте права на запись/чтение в директории attach.

Примечания

  • Если IMAP-соединение недоступно, скрипт всё равно парсит заголовки и тело письма, предполагая, что это текст.
  • Для сложных писем (например, с вложенными multipart-структурами) рекомендуется использовать IMAP-соединение для точного анализа.
  • Для диагностики можно добавить логирование:
    php
    file_put_contents('parse_log.txt', print_r($parsed_email, true), FILE_APPEND);
  • Если кодировка не распознана, используется UTF-8 по умолчанию.

Пример вывода

text
Структура письма:
Заголовки:
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
)
)
Обработка завершена.

Этот скрипт полностью соответствует требованиям и учитывает все возможные кодировки, обеспечивая надёжный анализ структуры письма.

1,5s
Как Grok может помочь?