公司用 osTicket 系統幾年了,最近把環境升級到 PHP8 和最新版 osTicket v1.18.1 後,同事回報踩到信件內容的 cid 圖片沒正常處理,就先追蹤一下信件處理流程,主要先追到 MIMEDecode 即可。
從官網文件 POP3/IMAP Settings Guide 得知,信件處理的觸發有從 crontab 和 api 的管道,目前就從 crontab 來追:
$ lsb_release -aNo LSB modules are available.Distributor ID: UbuntuDescription: Ubuntu 20.04.6 LTSRelease: 20.04Codename: focal$ php -vPHP 8.2.17 (cli) (built: Mar 16 2024 08:41:44) (NTS)Copyright (c) The PHP GroupZend Engine v4.2.17, Copyright (c) Zend Technologieswith Zend OPcache v8.2.17, Copyright (c), by Zend Technologies$ php api/cron.php
接著開始看 api/cron.php 程式碼,大概追到 include/class.cron.php 時,就可以看到 osTicket\Mail\Fetcher::run(); 和 include/class.email.php 檔案了,從 include/class.mailfetch.php 可以看到:
```php78 function processMessage(int $i, array $defaults = []) {79 try {80 // Please note that the returned object could be anything from81 // ticket, task to thread entry or a boolean.82 // Don't let TicketApi call fool you!83 return $this->getTicketsApi()->processEmail(84 $this->mbox->getRawEmail($i), $defaults);85 } catch (\TicketDenied $ex) {86 // If a ticket is denied we're going to report it as processed87 // so it can be moved out of the Fetch Folder or Deleted based88 // on the MailBox settings.89 return true;90 } catch (\EmailParseError $ex) {91 // Upstream we try to create a ticket on email parse error - if92 // it fails then that means we have invalid headers.93 // For Debug purposes log the parse error + headers as a warning94 $this->logWarning(sprintf("%s\n\n%s",95 $ex->getMessage(),96 $this->mbox->getRawHeader($i)));97 }98 return false;99 }```
接著在 processEmail 前埋一個 @file_put_contents('/tmp/debug-mail', print_r($this->mbox->getRawEmail($i), true)); ,如此處理信件時,原始格式就會被記錄在 /tmp/debug-mail 裡,下一刻就能再重現信件格式的處理流程
小改後面:
$ sudo cp api/cron.php api/cron-debug.php$ tail -n 5 api/cron-debug.php//LocalCronApiController::call();//$obj = new \TicketApiController('cli');print_r($obj->processEmail(file_get_contents('/tmp/debug-mail'), []));?>
如此運行時就可以看資訊:
$ php api/cron-debug.phpTicket Object([ht] => Array([ticket_id] => #[ticket_pid] =>[number] => #####...
接著要來研究信件處理流程,就來到了 include/api.tickets.php 檔案:
```phpfunction processEmail($data=false, array $defaults = []) {try {if (!$data)$data = $this->getEmailRequest();elseif (!is_array($data))$data = $this->parseEmail($data);print_r($data);} catch (Exception $ex) {throw new EmailParseError($ex->getMessage());}...```
繼續追 include/class.api.php 檔案:
```php238 function parseRequest($stream, $format, $validate=true) {239 $parser = null;240 switch(strtolower($format)) {241 case 'xml':242 if (!function_exists('xml_parser_create'))243 return $this->exerr(501, __('XML extension not supported'));244 $parser = new ApiXmlDataParser();245 break;246 case 'json':247 $parser = new ApiJsonDataParser();248 break;249 case 'email':250 $parser = new ApiEmailDataParser();251 break;252 default:253 return $this->exerr(415, __('Unsupported data format'));254 }255256 if (!($data = $parser->parse($stream)) || !is_array($data)) {257 $this->exerr(400, $parser->lastError());258 }259260 //Validate structure of the request.261 if ($validate && $data)262 $this->validate($data, $format, false);263264 return $data;265 }266267 function parseEmail($content) {268 return $this->parseRequest($content, 'email', false);269 }```
繼續追 include/class.mailparse.php 檔案,主要是追蹤 EmailDataParser -> Mail_Parse -> Mail_mimeDecode ,最後就是 include/pear/Mail/mimeDecode.php 的處理 MIMEDecode 的實作了。
剩下的工作就是研究它解析原始信件的流程,看看是 MIMEDecode 是否少了遞迴解,還是有什麼限制了:
沒有留言:
張貼留言