XSERVER でも使えるように
cakePHP3を使ったプロジェクトでメールを受信して添付ファイルを保存しようとしましたら。
まず、POP3用のライブラリをインストールしなきゃいけないことがわかりました。
で、VM上の Linux にインストールしてみました。
# pear channel-update pear.php.net
/usr/share/pear/Net にPOP3.php, Socket.php がインストールされました。
# pear install Mail_mimeDecode
/usr/share/pear/Mail にインストールされました。
でも、本番環境の XSERVER では root 権限でインストールなんてできないよね。
と、いうことで。
/usr/share/pear/のファイルを CAKEPHP_DIR /appendix/pear に無理やりコピーして使うことにしました。
require が動かない
require('Net/POP3.php');
require('Mail/mimeDecode.php');
としなきゃいけないのに、パスが効いてないから読み込めない。
PHP で get_include_path() を呼び出すと、次のようなインクルードパスが設定されていました。
".:/usr/share/pear:/usr/share/php"
そこで、
set_include_path(get_include_path() . PATH_SEPARATOR . CAKEPHP_DIR . '/appendix/pear/');
を呼び出すことで require がうまくいってくれました。
ポート番号995(POP3S)での受信設定
アカウント情報は、とりあえず MailServers データベースにでも置いといて、次のように取り込むようにしました。
$account = $this->MailServers->find()
->select(['pop3_server', 'pop3_port', 'pop3_account', 'pop3_psw'])
->first();
実際に POP3サーバに接続してログインする部分のコードは、こんな感じ
$pop3 = new Net_POP3();
$pop3->connect($account->pop3_server, $account->pop3_port);
$pop3->login($account->pop3_account, $account->pop3_psw);
$message_count = $pop3->numMsg();
$account->pop3_port を 995 にすると、接続ができずに悩みました。
pop3_server にプロトコルヘッダ ssl:// を付けてあげることで接続できました(^^)v
メール受信処理
実際には、message-id をDBに保存しておいて、すでに処理済みのメールかどうかをチェックしたりするのですが
メールの取り込みは次のような感じです
for($mail_no = 1; $mail_no <= $message_count; $mail_no++)
{
$msg = $pop3->getMsg($mail_no);
$decoder = new Mail_mimeDecode($msg);
$mime = $decoder->decode([
'include_bodies' => true,
'decode_bodies' => true,
'decode_headers' => true,
]);
$messageid = $mime->headers['message-id'];
$subject = $mime->headers['subject'];
$sender = $mime->headers['from'];
$date = $mime->headers['date'];
// メール解析
[$body, $attachments] = $this->analyze($mime);
// 必要な処理
}
今回は本文と添付ファイル情報を必要としたので、メールの mime 解析部分は、こんな感じです。
function analyze($mime)
{
$body = "";
$attachments = [];
if(!isset($mime->parts))
{
// シングルパート(テキストのみ)
$body = trim(mb_convert_encoding( $mime->body, "UTF-8", 'ASCII, JIS, UTF-8, SJIS' ));
}
else
{
// マルチパート
foreach($mime->parts as $part)
{
if((strtolower($part->ctype_primary) == 'text') && (strtolower($part->ctype_secondary) == 'plain'))
{
$body .= trim(mb_convert_encoding( $part->body, "UTF-8", 'ASCII, JIS, UTF-8, SJIS' )) . "\n";
}
else if((strtolower($part->ctype_primary) == 'application'))
{
$filename = $part->ctype_parameters['name'];
if(empty($filename))
{
$filename - $part->d_parameters['filename'];
}
if(0 < strlen($filename))
{
if(isset($part->body))
{
$attachment = [];
$attachment['filename'] = $filename;
$attachment['body'] = $part->body;
$attachments[] = $attachment;
}
}
}
else if(strtolower($part->ctype_primary) == 'multipart')
{
foreach($part->parts as $part2)
{
if(strtolower($part2->ctype_primary) == "text")
{
$charset = $part2->ctype_parameters['charset'];
$body = mb_convert_encoding($part2->body, 'UTF-8', $charset);
break;
}
}
}
}
}
return [$body, $attachments];
}
pear の修正
いろいろエラーが出たので、pear 側のソースも変更しました。
■Net/POP3.php 変更点
/* 第3パラメータが非推奨になっていたので削除
define('NET_POP3_STATE_DISCONNECTED', 1, true);
define('NET_POP3_STATE_AUTHORISATION', 2, true);
define('NET_POP3_STATE_TRANSACTION', 4, true);
*/
define('NET_POP3_STATE_DISCONNECTED', 1);
define('NET_POP3_STATE_AUTHORISATION', 2);
define('NET_POP3_STATE_TRANSACTION', 4);
// クラス名と同名のコンストラクタが非推奨なので変更
// function Net_POP3()
function __construct()
■Mail/mimeDecode.php 変更点
// ISO-2022-JPのメールヘッダを正しく解析してくれない。
function _decodeHeader($input, $default_charset=false)
{
if (!$this->_decode_headers) {
return $input;
}
// iconv_mime_decode を使うように変更。
$input = iconv_mime_decode($input, ICONV_MIME_DECODE_CONTINUE_ON_ERROR);
// Remove white space between encoded-words 以下を削除。
return $input;
}
// はだかのHTMLテキストが渡されてエラーでまくりなので変更
function _quotedPrintableDecode($input)
{
// Remove soft line breaks
$input = preg_replace("/=\r?\n/", '', $input);
$input = quoted_printable_decode($input);
// Replace encoded characters 以下を削除
return $input;
}
まとめ
XSERVERにインストールできないとなると、AWS EC2 あたりにサーバー移動しなきゃならないかな?と悩んでいたので、受信できるようになって助かりました。
めでたしめでたし。