2024年4月11日 星期四

PHP 開發筆記 - 修正 osTicket v1.18.1 信件處理流程 (Mail Parser / Mail Fetch / MIMEDecode)


經歷一陣子的追蹤,發現 osTicket v1.18.1 的信件處理流程更新的不錯,但在一個關鍵的格式拼裝上出了錯誤,目前就發個 PR 讓團隊評估是否能修正了

這陣子研究 osTicket v1.18.1 時,信件處理分成兩個部分,一個是信件下載,另一個是信件解析。之前設法先把他信件架在過程中,埋了一個機制把信件存起來,接著去研究它的 MIMEDecode 流程,並猜測這邊要補強,實際上是他下載信件後,要組成 MIME 格式有問題,才使得信件解析有問題


        public function getRawEmail(int $i) {
-           return $this->getRawHeader($i) . $this->getRawContent($i);
+           return trim($this->getRawHeader($i)) . "\r\n\r\n" . $this->getRawContent($i);
        }

透過這次也研究了 osTicket v1.18 採用了 laminas-mail 來處理信件下載流程,整體上跑 api/cron.php 可以看到:

# php8.1 cron.php
@class.mail.php - Imap class: __construct
@Storage/Imap.php: __construct 
@Storage/Imap.php: selectFolder(INBOX) 
@Storage/Imap.php: countMessages()
@Storage/Imap.php: getRawHeader(1, , 0)
@Storage/Imap.php: getRawContent(1, )
@class.mail.php, Imap class: markAsSeen(1)
@Storage/Imap.php: setFlags(1, Array)
@class.mail.php, Imap class: expunge()
@Storage/Imap.php:close()

而在 class.mail.php 在 v1.16 是看不到的,可在 osTicket/osTicket/blob/1.16.x/include/class.mailfetch.php 觀看直接用 PHP imap_* 系列的函式做事,而在 v1.17 起多了 class.mail.php 檔案,在其檔案內可以看到 getRawEmail() 的實作分成 getRawHeader() + getRawContent() 

再往下追就會發現架構也變得漂亮。趁這次多了解了 osTicket ,而為了這次任務,解題思維:
  1. 設法用 Docker 建立 osTicket 測試環境
  2. 設法在 osTicket 處理信件流程中,取出一個 eml 檔案實驗
  3. 設法在 osTicket 架構下,建立匯入 eml 檔案作為重現 MIMEDecode 的測試
  4. 設法直接用 MIMEDecode 測試流程
  5. 追蹤 osTicket IMAP 信件下載流程
沒想到最後一步才發現問題的根源,若一開始先懷疑信件下載流程,應當可以秒解任務。後續再看送出的 PR 有沒緣被收了