メール本文を取得して本文を変更する

さて無事にPEARもインストールしたことだし、
続きの作業にかかろう。


1.メール受信(トリガー)

2.メールの本文を取得し、メール本文を変更

3.変更したメールを任意のメールアドレスへ転送

メールの本文を取得し、メール本文を変更

まずメールの取得。
これはサイトからまんまパクった。

<?php
  require_once 'Mail/mimeDecode.php';
  // メールデータ取得
  $params['include_bodies'] = true;
  $params['decode_bodies']  = true;
  $params['decode_headers'] = true;
  $params['input'] = file_get_contents("php://stdin");
  $params['crlf'] = "\r\n";
  $structure = Mail_mimeDecode::decode($params);

  //送信者のメールアドレスを抽出
  $mail = $structure->headers['from'];
  $mail = addslashes($mail);
  $mail = str_replace('"','',$mail);

  //署名付きの場合の処理を追加
  preg_match("/<.*>/",$mail,$str);
  if($str[0]!=""){
    $str=substr($str[0],1,strlen($str[0])-2);
    $mail = $str;
  }
  /*
   *「$structure->headers['to']」で送信元のメールアドレスも取得できます。
   */

  // 件名を取得
  $diary_subject = $structure->headers['subject'];
  
  switch(strtolower($structure->ctype_primary)){
    case "text": // シングルパート(テキストのみ)
      $diary_body = $structure->body;
      break;
    case "multipart":  // マルチパート(画像付き)
      foreach($structure->parts as $part){
        switch(strtolower($part->ctype_primary)){
          case "text": // テキスト
            $diary_body = $part->body;
            break;
          case "image": // 画像
            //画像の拡張子を取得する(小文字に変換
            $type = strtolower($part->ctype_secondary);
            //JPEGチェック(GIFやPNG形式の画像チェックなども可
            if($type != "jpeg" and $type != "jpg"){
              continue;
            }
            //添付内容をファイルに保存
            $fp = fopen("/tmp/picture.jpg" . $type,"w" );
            $length = strlen( $part->body );
            fwrite( $fp, $part->body, $length );
            fclose( $fp );
            break;
        }
      }
    break;
    default:
    $diary_body = "";
  }
  /*
   * 取得したメールアドレス、タイトル、本文、画像を使用してデータベースなどに取り込む
   */
?> 

$diary_subjectにはメールのタイトルが格納されています。
$diary_bodyにはメール本文が格納されています。
「/tmp/picture.jpg」には添付した画像が保存されます。
86. stdinからのメール処理でメール情報を取得する | 日経 xTECH(クロステック)


添付まで保存できるなんて便利だ。
まぁ使うことはないが・・・


で、あとは取得したものを
文字列変数を駆使していじくりこねる。


ここではまったのがやはり文字コードだ。


とある文字列で中身を検索するということを
やりたかったのだが、どうもうまく検索できない。


というか明らかにメール本文にある文字列を
検索してもなぜかひっかからないのだ。


よく考えればわかったことだが、
メール本文の文字コードは「ISO-2022-JP」なのだ。

ISO-2022-JPは、インターネット上(特に電子メール)などで使われる日本の文字用の文字符号化方式ISO/IEC 2022エスケープシーケンスを利用して文字集合を切り替える7ビットのコードであることを特徴とする (アナウンス機能のエスケープシーケンスは省略される)。俗に「JISコード」と呼ばれることもある。
ISO-2022-JP - Wikipedia


で、さっそく確かめてみる。

$mojicode = mb_detect_encoding($diary_body);
print "$diary_body の文字コードは $mojicode です。";

出力:$diary_body の文字コードは JIS です。

参考:文字コードの変換


ISO-2022-JP」と出力されると思ったが、
「JIS」と表示されたのが意外だったが
調べてみるとどうやらそうらしい。

PHP文字コード MIME エイリアス
JIS ISO-2022-JP -

PHP の mbstring に関するメモ


で、自分が作成したプログラムは「EUC-JP」だったので
それに変換してから検索する必要があった。


ちなみに今主流の文字コードは「UTF-8」で
ほとんどのWEBプログラマがこのコードで
コーディングしていることだと思う。


自分の場合は、今までずっとそれでやってきたので
めんどくさいのでそのままでやった。

$diary_bodyEUC = mb_convert_encoding($diary_body,"EUC-JP", "JIS");

mb_convert_encoding - 文字エンコーディングを変換する


ここで注意することはmb_convert_encodingの
第三引数をautoにしないことだ。


autoにすれば勝手に文字コードを判定してくれるらしいのだが、
どうもそれは危険だと下記のサイトに書いてあった。

何も指定しなければ「auto」というパラメータになるのだが、このautoはかなりくせ者だ。何も指定していない場合や、autoを指定すると「ASCII,JIS,UTF-8,EUC-JP,SJIS」の用に展開される。が、マルチバイトを計る上でASCIIが一番先頭である時点ですでに欠陥である。
http://hain.jp/index.php/tech-j/2007/02/13/%EF%BC%B0%EF%BC%A8%EF%BC%B0%E3%81%AE%E6%96%87%E5%AD%97%E5%8C%96%E3%81%91


よってautoでなくて(省略せずに)きちんと文字コードを指定する。
以下のような形でもよいと思うが、これがいいのか危険なのかはわからない・・・

$diary_bodyEUC = mb_convert_encoding($diary_body,"EUC-JP", mb_detect_encoding($diary_body));


まぁ機会があったら調べることにして
これで実際に検索して見た。

if ( mb_ereg ( "検索文字列", $diary_bodyEUC ) ) {
	$mailsendflg = 0;
}


ここでもいろいろ調べてみると
検索する関数について議論があって、
以下のような記事を見つけた。

どうも、mb_ereg系の関数では、UTF-8をうまく扱えないようです。
http://ifs.seesaa.net/article/26300967.html

普段は内部エンコーディングとファイルの文字コードなどは統一された環境が一般的だと思います。そういったときには上記の設定を意識せずに使うことができるのでこの関数を使用して設定の変更を行なうことはないと思います。
mb_eregで日本語検索すると・・ - アシアルブログ


でもどうやら「UTF-8」の時らしいので
とりあえず、mb_eregでうまくいったのでそれでいくことにした。


また、PHP正規表現については以下を参考にした。
参考:正規表現メモ


さて、検索はOK。
あとは文字列を抜き出したりする作業だが、
これらは以下の関数などを使うことで特に不具合なくできた。


【 ほでなすPHP 】 関数ミニリファレンス -> マルチバイト文字列関数


またtrim関数だと全角スペースがtrimできないので
以下の関数をパクった。

function mb_trim($str, $chars="\s "){
  $str = mb_ereg_replace("^[$chars]+", "", $str);
  $str = mb_ereg_replace("[$chars]+$", "", $str);
  return $str;
}

"院","法","鼻"などの文字がtrimをかけると化ける。その時の対処法。

そもそもこんな風に化けるのは、以下のような原因のため。

1.PHPのtrim()が2バイト文字に対応していない。

2.そのため、PHPのtrimは問答無用で文字列の最後のバイトの「0xA0」を除く。
  (EUCでスペースが「0xA0」のため)

3.その時、2バイト文字が最後の場合、かつその文字が"院","法"の場合は、
  これらの文字の2バイト目のコードが「0xA0」のため、切り取られる。

4.切り取られた文字は化けて違う文字になる。

5.結局、対応は自前でmb_trim()を作る。
http://note.area93.net/it/?p=71


さて、あとはそのいじくったメール
本文を任意のメールに送るだけだ。


長くなったので別の記事へ・・・


続き
PEARを利用してメールを送信する。 - ちぇ・ゲバ男のメモ


他参考:http://homepage2.nifty.com/sak/w_sak3/doc/sysbrd/sak3php.htm