Пишем свой сборщик писем на PHP (2 часть из 3)

Скрипт для скачивания писем (loader.php)

<?php
require_once "func.php";//подключаем функции
require_once "connect.php";//подключаем настройки к MySQL
 
wr("\n=============================\n");
 
//некоторые строки уже прокомменитированы в коде (см. reader.php),
//поэтому оставим их без комментариев
set_time_limit(0);
$lock = "loader.lock";
$aborted = file_exists($lock) ? filemtime($lock) : false;
$fp = fopen($lock,'w');
register_shutdown_function(function() use ($fp, $lock) {
    wr("shutdown");
    flock($fp, LOCK_UN);//снимаем блокировку с файла
    fclose($fp);//закрываем файл
    unlink( __DIR__ . DIRECTORY_SEPARATOR . $lock);//удаляем файл
});
if(!flock($fp,LOCK_EX|LOCK_NB)){
    wr("busy\n");//пишем в лог, что занято
}else{
    if($aborted){
        wr("Aborted\n");
    }
 
    //составим список только тех почтовых ящиков,
    //сообщения которых еще не скачаны
    $sql = "SELECT b.*
            FROM mailboxes b
            JOIN(
                SELECT mailbox_id FROM messages GROUP BY mailbox_id
            )m ON m.mailbox_id = b.id";
    $res = mysql_query($sql);
    $mailboxes = array();
    while($row = mysql_fetch_array($res)){
        array_push($mailboxes,$row);
    }
 
    //перебор почтовых ящиков
    foreach($mailboxes as $mailbox){
        $mailbox_id = $mailbox['id'];
        $host = $mailbox['host'];//адрес почтового сервера
        $port = $mailbox['port'];//порт почтового сервера
        $user = $mailbox['email'];//имя пользователя (почтовый ящик)
        $password = $mailbox['password'];//пароль к почтовому ящику
        $ssl = $mailbox['is_ssl'] ? "/ssl" : "";
        //строка подключения
        $conn = "{{$host}:{$port}{$ssl}}";
        wr("Read $user, conn = $conn");
 
        //открываем IMAP-поток
        $mail = imap_open($conn,$user,$password);
        if(!$mail){
            //пишем в лог сообщение о неудачной попытке подключения
            wr("Error opening IMAP. " . imap_last_error());
            continue;//переходим к следующему ящику
        }
 
        mysql_query("SET AUTOCOMMIT=0");
        mysql_query("START TRANSACTION");
 
        //получаем список сообщений, которые необходимо скачать с почтового ящика
        $sql = "SELECT *
                FROM messages
                WHERE mailbox_id = $mailbox_id AND is_ready = false";
        $res = mysql_query($sql);
        while($message = mysql_fetch_array($res)){
            $message_id = $message['id'];//ID письма в базе данных
            $message_uid = $message['uid'];//уникальный номер письма
            $headerRaw = getHeaderRaw($mail,$message_uid);//технический заголовок письма
            $header = getHeader($mail,$message_uid);//заголовок письма
            $subject = getDecodedHeader($header->subject);//тема письма
            $headerDate = strToMysqlDate($header->date);//дата письма
            $body_text = getTextBody($mail,$message_uid);//содержимое письма в виде простого текста
            $body_html = getHtmlBody($mail,$message_uid);//содержимое письма в формате html
 
            //получение адресов из заголовка письма
            $address_map = array();
            $address_types = array('to','from','reply_to','sender','cc','bcc');
            foreach($address_types as $address_type){
                getAddress($header,$address_type,$address_map);
            }
 
            foreach($address_map as $key => $arr){
                foreach($arr as $obj){
                    $type = $key;
                    $address = "$obj->mailbox@$obj->host";//склеиваем email
                    $sql = "INSERT INTO addresses(message_id,type,email)
                            VALUES($message_id,
                            '" . mysql_real_escape_string($type) . "',
                            '" . mysql_real_escape_string($address) . "')";
                    mysql_query($sql) or wr(mysql_error());
                }
            }
 
            //считываем вложения и получаем кол-во вложений,
            //которое записываем в базу данных
            $attachCount = loadAttaches($mail,$message_uid,$message_id);
 
            $sql = "UPDATE messages
                    SET subject = '" . mysql_real_escape_string($subject) . "',
                        body_text = '" . mysql_real_escape_string($body_text) . "',
                        body_html = '" . mysql_real_escape_string($body_html) . "',
                        header = '" . mysql_real_escape_string($headerRaw) . "',
                        message_date = '" . mysql_real_escape_string($headerDate) . "',
                        attachment_count = $attachCount,
                        modify_date = now(),
                        is_ready = true
                    WHERE id = $message_id";
            mysql_query($sql) or wr(mysql_error());
            mysql_query("COMMIT");
        }
 
    }
 
}
?>

2 комментария

  1. mr.dfox:

    Что то на вскидку не могу понять, для чего прием заголовком и запись тела сообщения с вложениями производиться в 2 подхода?

    • Naik:

      Точно уже не помню… Скорее всего, из-за того, что функция imap_fetch_overview возвращает частичную информацию о письме.
      Скачивание и сохранение содержимого письма и вложений может занять длительное время. Поэтому мы быстренько сохраняет UID новых писем. А дальше спокойно по очереди вытаскиванием письма со всем содержимым. Один скрипт готовит данные для скачивания, а второй скачивает, не мешая друг другу.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *