受信メールでPHPの起動から添付ファイルの保存まで(さくらインターネット)


さくらインターネットレンタルサーバ環境にて、受信メールによるPHPプログラムの
起動に成功しましたので以下にメモします。

http://www.cpa-lab.com/tech/0143

を参考にsakuraエディターでテキストファイルを編集してftpでアップした。

このようにエラー発生

----- The following addresses had permanent fatal errors -----
<post@xxxx.com>
   (reason: 127)

  ----- Transcript of session follows -----
/home/xxxx/www/work/mail/example.php: not found
554 5.3.0 unknown mailer error 127

telnetコマンドラインでもエラー

%ls
example.php
%./example.php
./example.php: Command not found.


http://www.y-tti.com/blog/2007/06/mailfilter.php
ここを見て”保存設定 EUC LF(改行)としたら成功しました。

コマンドラインも成功

%ls
example.php
%./example.php
X-Powered-By: PHP/5.2.8
Content-type: text/html

example.php

#!/usr/local/bin/php

<?php

$content = null;
$fp=fopen("php://stdin",'r') or die('File Open Error');
$fpw=fopen("mail.txt",'w');

while( !feof($fp) ){
    $content .= fgets( $fp ,1024);
}
fputs($fpw,$content);

?>


実行結果 mail.txt が出力されました。

崖っぷちWEBデザイナーブログ で助かりました。
ありがとうございます。

添付ファイルの保存は、ここの class ReceiptMailDecoder を使うことにする。
http://d.hatena.ne.jp/ya--mada/20080415/1208318475

PEARのインストールが必要なのでここを見ながらインストール。
http://masha.maakikaku.jp/2008/05/gopearpear.php

Go-PEARは便利でした。
一番下にスクロールするところが判り難い。
Start Web Frontend of the PEAR Installer >> をクリックする必要がある。


サンプルをmail.txtを読み込んで処理するように修正。
デバッグしやすいように2つのPHPに分けて実行。

<?php
require_once('ReceiptMailDecoder.class.php');

$fp = fopen("mail.txt","r");
$body = "";
while (!feof($fp)){
	$body .= fgets($fp,1024);
}

$decoder =& new ReceiptMailDecoder($body);
// To:アドレスのみを取得する

$toAddr = $decoder->getToAddr();	print "$toAddr <br>";
// To:ヘッダの値を取得する

$fromAddr = $decoder->getFromAddr();		print "$fromAddr <br>";
// from:ヘッダの値を取得する

$toString = $decoder->getDecodedHeader( 'to' );
// Subject:ヘッダの値を取得する

$subject = $decoder->getDecodedHeader( 'subject' );	print "$subject  <br>";
// text/planなメール本文を取得する

$body = mb_convert_encoding($decoder->body['text'],"eucjp-win","jis"); print "$body  <br>";
// text/htmlなメール本文を取得する

$body = mb_convert_encoding($decoder->body['html'],"eucjp-win","jis"); print "$body  <br>";
// マルチパートのデータを取得する
if ( $decoder->isMultipart() ) {
    $tempFiles = array();
    $num_of_attaches = $decoder->getNumOfAttach();
    for ( $i=0 ; $i < $num_of_attaches ; ++$i ) {
        /*
         * ファイルを一時ディレクトリ _TEMP_ATTACH_FILE_DIR_ に保存する
         * 一時ファイルには tempnam()を使用する
         * この部分は使用に合わせて変更して下せい
         */
        $fpath = tempnam("./tmp", "todoattach_" );
    	print "fpath=$fpath <br>\n";
//        $fpath = tempnam( _TEMP_ATTACH_FILE_DIR_, "todoattach_" );
        if ( $decoder->saveAttachFile( $i, $fpath ) ) {
            $tempFiles["$fpath"] = $decoder->attachments[$i]['mime_type'];
        }
    }
}
?>


class ReceiptMailDecoder のサンプルは、テンポラリーのファイル名を使うようになっているので
受信メールよりファイル名を取得してそのファイル名で保存するように修正した。

$filename = $this->attachments[$index]['file_name'];
でファイル名が取得できる。

    function saveAttachFile ( $index, $str_path ) {
	
	if ( !file_exists($str_path) ) {
	    if ( !is_writable(dirname($str_path)) ) {
		return false;
	    }
	}
	else {
	    if ( !is_writable($str_path) ) {
		return false;
	    }
	}
	
	if ( !isset($this->attachments[$index]) ) {
	    return false;
	}
	
	$filename = $this->attachments[$index]['file_name'];    	
    print "filename = $filename <br>\n";
//	if ( $fp=fopen($str_path, "wb") ) {
	if ( $fp=fopen($filename, "wb") ) {		
	    fwrite($fp, $this->attachments[$index]['binary'] );
	    fclose($fp);
	    return true;
	}

    	
	return false;
    }


ここまでで、受信メールでPHPの起動から添付ファイルの保存までのプログラムが出来た。
私のアプリケーションの場合受信ファイル名が重要なのでこのあたりの調整が必要。


次に2つのPHPをくっつけたらうまく動かない。

2つのPHPをくっつけて実行したらうまくいかない。
telnetにて

%
%php -i >php.htm
%

を実行してパスを確認したら

Loaded Configuration File が /usr/local/php-5.2.8/lib/php.ini

になっていた。

ソースにini_setを追加してうまくいきました。

ini_set('include_path', '/home/xxxx/www/work/pear/php');
require_once('ReceiptMailDecoder.class.php');


先人たちの記事にてここまでくることが出来ました。
感謝します。


作成した、受信メールで起動するPHPのソース

#!/usr/local/bin/php

<?php
print "php start!!\n";

/*標準出力をmail.txtに保存*/
$content = null;
$fp=fopen("php://stdin",'r') or die('File Open Error');
$fpw=fopen("mail.txt",'w');
$fplog=fopen("log.txt",'a');

//fputs($fplog, "log open \n");

while( !feof($fp) ){
    $content .= fgets( $fp ,1024);
}
fputs($fpw, $content);

//fputs($fplog, "mail.txt write \n");


/**/
ini_set('include_path', '/home/anakureon/www/work/pear/php');
require_once('ReceiptMailDecoder.class.php');

print "open mail.txt\n";

$fp = fopen("mail.txt","r");
$body = "";
while (!feof($fp)){
	$body .= fgets($fp,1024);
}

$decoder =& new ReceiptMailDecoder($body);
// To:アドレスのみを取得する

$toAddr = $decoder->getToAddr();	print "$toAddr <br>";
// To:ヘッダの値を取得する

$fromAddr = $decoder->getFromAddr();		print "$fromAddr <br>";
// from:ヘッダの値を取得する

$toString = $decoder->getDecodedHeader( 'to' );
// Subject:ヘッダの値を取得する

$subject = $decoder->getDecodedHeader( 'subject' );	print "$subject  <br>";
// text/planなメール本文を取得する

$body = mb_convert_encoding($decoder->body['text'],"eucjp-win","jis"); print "$body  <br>";
// text/htmlなメール本文を取得する

$body = mb_convert_encoding($decoder->body['html'],"eucjp-win","jis"); print "$body  <br>";
// マルチパートのデータを取得する
if ( $decoder->isMultipart() ) {
    $tempFiles = array();
    $num_of_attaches = $decoder->getNumOfAttach();
    for ( $i=0 ; $i < $num_of_attaches ; ++$i ) {
        /*
         * ファイルを一時ディレクトリ _TEMP_ATTACH_FILE_DIR_ に保存する
         * 一時ファイルには tempnam()を使用する
         * この部分は使用に合わせて変更して下せい
         */
        $fpath = tempnam("./tmp", "todoattach_" );
    	print "fpath=$fpath <br>\n";
//        $fpath = tempnam( _TEMP_ATTACH_FILE_DIR_, "todoattach_" );
        if ( $decoder->saveAttachFile( $i, $fpath ) ) {
            $tempFiles["$fpath"] = $decoder->attachments[$i]['mime_type'];
        }
    }
}
/**/

$created = date('Y-m-d H:i:s');  
fputs($fplog, "$created,$fromAddr,\n");

?>