1. Приветствуем Вас на неофициальном форуме технической поддержки XenForo на русском языке. XenForo - коммерческий форумный движок от бывших создателей vBulletin, написанный на PHP.

Собираем логи отправки писем

Тема в разделе "Оптимизация XenForo", создана пользователем infis, 27.05.2016.

Загрузка
  1. infis

    infis Местный

    Регистрация:
    27.06.11
    Сообщения:
    5 966
    Симпатии:
    3 548
    Версия XF:
    1.5.9
    Не секрет, что иногда возникает вопрос, а было ли оповещение какого-нибудь участника, но сам XenForo логов таких не ведет, а логи почтового сервера поднимать не всегда удобно. Да и не факт, что есть доступ к логам почтовика.
    У меня сервер почтовый свой, но все таки в случае поиска какого-нибудь письма лень перебирать логи, да и иногда нужно тело самого письма глянуть.
    В связи с этим возникла мысль, а почему бы не собирать логи отправки писем в базе. Но дело осложнилось тем, что написать плагин, который бы встраивался в цепочку подготовки и отправки писем, почти невозможно, так как в XenForo по какой-то причине не все сделано через модель. Более того, в одном месте вообще применяется прямой запрос. Таким образом "поймать" помещение в таблицу и удаление из таблицы нужных записей с помощью плагинов не представляется возможным.
    Но есть один неплохой инструмент для отслеживания событий в самих таблицах в базе данных. То есть, если у Вас есть доступ к созданию триггеров в базе данных, значит, можно и ловить нужные события типа INSERT, UPDATE и DELETE.
    Так как сервер базы данных мой, то у меня, естественно, с триггерами проблем не возникло.

    Итак, сначала создаем таблицу, в которую будем помещать логируемые письма:
    Код:
    CREATE TABLE mail_log (
      mail_queue_id int(10) NOT NULL,
      mail_data mediumblob NOT NULL,
      queue_date int(10) UNSIGNED NOT NULL,
      insert_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
      delete_time timestamp NULL DEFAULT '0000-00-00 00:00:00',
      mailed_user_id int(10) UNSIGNED DEFAULT NULL
    )
    ENGINE = INNODB;
    Как видим, по сути копируем таблицу xf_mail_queue, добавляя поля для хранения времени помещения записи в таблицу (почти всегда равна queue_date), удаления ее из таблицы (что означает, что письмо отправлено), а также идентификатор оповещаемого пользователя. С ним пришлось повозиться, так как изначально этот идентификатор отсутствует, а идентифицировать можно только, извлекая информацию из тела письма. Естественно, пришлось обходиться строковыми функциями в триггере, так как встроенных средств обработки сериализованного массива PHP в MySQL нет.
    В общем получился такой триггер на обработку события вставки записи в таблицу почтовой очереди:
    Код:
    CREATE
       DEFINER = 'root'@'localhost'
    TRIGGER trigger_mail_add
       AFTER INSERT
       ON xf_mail_queue
       FOR EACH ROW
    BEGIN
      SET @user_email = SUBSTRING_INDEX(SUBSTRING_INDEX(NEW.mail_data,'>',1),'<',-1);
      SET @user_id = (SELECT user_id FROM xf_user WHERE email=@user_email);
      INSERT INTO mail_log (mail_queue_id, mail_data, queue_date, mailed_user_id) VALUES (NEW.mail_queue_id, NEW.mail_data, NEW.queue_date, @user_id);
    END
    Ну и последний штрих - триггер на удаление из таблицы очереди. Время удаления - это и есть время отправки письма, так как удаление из таблицы происходит после успешной отправки письма.
    Код:
    CREATE
       DEFINER = 'root'@'localhost'
    TRIGGER trigger_mail_delete
       AFTER DELETE
       ON xf_mail_queue
       FOR EACH ROW
    BEGIN
      UPDATE mail_log SET delete_time = NOW() WHERE mail_queue_id=OLD.mail_queue_id;
    END
    Теперь независимо от того, каким образом добавили в очередь письмо и как его затем обработали, мы всегда знаем, когда это происходило. Ну и по идентификатору пользователя (user_id) элементарно можем фильтровать все письма.

    Теперь некоторым нытикам по поводу неполучения оповещений я всегда могу быстро сказать, сколько и когда ему было отправлено оповещений. А вот недоставка писем - это уже другая история, которая далеко не всегда зависит от администрации ресурса. Поэтому разборки переносятся на новый уровень :)
     
    Mirovinger нравится это.

Поделиться этой страницей