「php」タグアーカイブ

【php】IMAPでメールをチェックしてコマンド実行するスクリプト

sc20150214235107

追記:VerUP他

RaspberryPiに繋いでるスピーカーを常時通電させているので、時報だけ言わせてるのはもったいないと思い、メールの重要な着信をお知らせしようかと。

以下、時報の時の記事。http://blog.ahh.jp/?p=6418

久々に、PHPスクリプトをこしらえてみました。超ど忘れしとる(;´Д`)

まんま、スクリプトを貼ります。

アカウントとパスワードを書き換えれば、どこでも動くんではないでしょうか(Gmailなら)INBOXに続くパスを加えれば、振り分けルール等を対象に出来ます。

cronとかで定期的に動かす感じでしょうか。

注意する点として、IMAPサーバに負荷を掛けたくなかったので、純粋な最新メールを取得する訳ではありません。厳密には日付ソートによるメールではなく、メールサーバが受信した最新のメールとなります。

どういう事かというと、IMAPサーバの構成を変更した時に、メールの受信が前後する場合があります。レアケースですけどね(;^ω^)テストしてたら分かったんだけども・・。

コマンドには好きなものを書けるはずです。CRON内なら、必要な環境変数をCRONに渡す必要があるので注意。Pathとか

棒読みちゃんで、件名とか喋らしたいんだけども、さすがにラズパイには厳しいでしょうね。

追記:

ちょっとだけバージョンアップしました。あと、サンプル用に、ゆっくりの音声を用意しました。よければどうぞ。

  • 音声サンプル(ゆっくり音声)
  • PHPスクリプト(PHP本体と音声再生用のシェルスクリプト)
    ※スクリプト内のパスなどは、適宜変更してください

動作説明:IMAP新メールから取得していき、指定時間内に受信したもの&未読メールで、指定ドメイン毎に、独自コマンドを実行できます。低負荷で動作します。送り元メールアドレスを、正規表現にて限定してます。

RaspberryPi(Rasbian/Debian)上で動作確認してますが、環境依存はしないはずです。PHP5/PHP5-IMAPパッケージが必要です。IMAPからの戻りに数秒掛かります。メモリの消費もType-Bなら大丈夫なようです。

<?php
date_default_timezone_set(‘Asia/Tokyo’);
/*
* IMAPから新しいメールを取得し、条件に合致した場合、コマンド実行
* (条件:未読・指定送元・時間)
*/

//IMAPサーバ設定
define(‘GMAIL_HOST’, ‘imap.googlemail.com’);
define(‘GMAIL_PORT’, 993);
define(‘GMAIL_ACCOUNT’, ‘foo@gmail.com’);
define(‘GMAIL_PASSWORD’, ‘password’);
define(‘SERVER’,'{‘.GMAIL_HOST.’:’.GMAIL_PORT.’/novalidate-cert/imap/ssl/readonly}’);
//設定
define(‘TARGET_MAILS’, 20);        //取得するメール数(最新から)
define(‘TARGET_HOURS’, 1);        //最新メールとする時間(時)
//
define(‘FIND_CMD’, );            //実行するコマンド(その都度)
define(‘FIND_CMD_ONES’, ‘~nabe/check_imap/talk_maildesu.sh’);    //実行するコマンド(最後に一度だけ)

//対象のメール送元(正規表現記法 , コマンド)
//※コマンドが空の場合、FIND_CMDが実行される

$TARGET_SENDER = array(
    ‘/twitter\./’ => ‘~nabe/check_imap/talk_twitter.sh’,
    ‘/rakuten\.co/’ => ‘~nabe/check_imap/talk_rakuten.sh’,
    ‘/amazon\.co/’ => ‘~nabe/check_imap/talk_amazon.sh’,
    ‘/yahoo\.co/’ => ‘~nabe/check_imap/talk_yahoo.sh’,
    ‘/nicovideo\.jp$/’ => ‘~nabe/check_imap/talk_nikoniko.sh’

);
$find_mail = 0;
//IMAP
if (($mbox = @imap_open(SERVER.”INBOX”, GMAIL_ACCOUNT, GMAIL_PASSWORD)) == false) {
    echo “canot connect server.”;
    exit(1);
}
//件数取得
$status = imap_status($mbox, “{“.GMAIL_HOST.”}INBOX”, SA_ALL);
if($status->messages != 0) {
    $mail = null;
    //取得
    for( $mailno = $status->messages – TARGET_MAILS;$mailno <= $status->messages; $mailno++ ) {
        $head = imap_header($mbox, $mailno);
        //未読?
        if(@$head->Unseen == ‘U’){
            //整形
            $mail[$mailno][‘date’] = $head->date;
            $mail[$mailno][‘address’] = $head->from[0]->mailbox.’@’.$head->from[0]->host;
            if( !empty($head->subject) ) {
                $mhead = imap_mime_header_decode($head->subject);
                $mail[$mailno][‘subject’] = ”;
                foreach( $mhead as $key=>$value) {
                    if( $value->charset != ‘default’ ) {
                        $mail[$mailno][‘subject’] .= mb_convert_encoding($value->text,’UTF-8′,$value->charset);
                    }else{
                        $mail[$mailno][‘subject’] = $value->text;
                    }
                }
            }
            $mtime = strtotime($mail[$mailno][‘date’]);
            $tdiff = abs(time() – $mtime);
            //対象の最新メール?
            if($tdiff < TARGET_HOURS * 3600){
                $cmd = “”;
                foreach($TARGET_SENDER as $key=>$value){
                    if(preg_match($key,$mail[$mailno][‘address’])){
                        //対象メール発見
                        //var_dump($mail[$mailno]);
                        $cmd = FIND_CMD;
                        if($value != ”) $cmd = $value;
                        $find_mail++;
                    }
                }
                //コマンド実行
                @exec($cmd);
            }

        }
    }
}
@imap_close($mbox);
if($find_mail > 0) {
    //コマンド実行
    @exec(FIND_CMD_ONES);
}
exit(0);
?>

テストはまだ数日程度ですので、自己責任にてお願いします。

コード内で、件名もエンコード取得してますが、特に利用してません。件名に引っ掛けて、動作するようにもできます。適当に改造してください。

私の場合は、時報と重なってしまうので、コードの上部に「sleep(30);」とか入れて、ちょっと遅らせてます(30秒)

sc20150215231754

そういや、無意識にPHPスクリプトを書いて、Windowsからラズパイにコピーして動作させようとしたら、動かない・・。

ラズパイに、PHPを入れてませんでしたw(;^ω^)そういや、ウェブサービス使ってないか。

以下、もしPHP環境が入ってなかった場合の手順です。

aptitude updateと、aptitude upgradeは事前に行っておく(パッケージを最新にしておく)

aptitude install apache2 php5 php5-imap

として、3パッケージ分入れます。ついでなので、apache2(Webサーバ)も入れておく。

ラズパイでの、php5-imapパッケージは、デフォでSSL利用可能らしいので、とても簡単です。

※他に必要なパッケージの案内が出たら、全部入れておこう

ここまで。

上のPHPコードのサンプルでは、aplayコマンドでWAV音声を鳴らしてます。これは標準で入っていたと思う。

CRONに登録する場合は、以下の感じになるかなぁ・・と思います。

*/5 * * * * /usr/bin/php (スクリプトを置いた場所)/chk_imap.php

これで、5分毎にスクリプトを実行してくれます。

夜間に鳴らしたくない場合は、*/5 6-23 * * * とかにすれば、AM6ーPM11までの稼働になります。詳しくはCRONTABで検索。

【言語】Perlの最新版5.20が公開だってよ

sc20140603160105

Perlの最新版5.20が公開だそうです・・。

http://perlnews.org/2014/05/perl-5-20-released/

私も以前はPerlに浸って、周囲にPerlの素晴らしさを布教しまわっていた時代がありました。

AWKユーザーと激しく対立する時もありました。

もうそのほとんどの記憶が消し飛んでしまいましたが、確実に言えることがあります。

Perl正規表現だけは、今だにハッキシと身についております

RubyやPythonとか、様々な言語が台頭して、もう過去の遺物ととらわれがちですが、だからこその良い意味で枯れた信頼性の高いスクリプト記述として、また見直しても良いかな・・とか、思ったり思わなかったり。

sc20140603161504

次世代のPerl6のロゴです。

( ゚д゚)・・・・・

( ゚д゚)・・・・・

( ゚д゚)・・・・・

( ゚д゚)・・・・・

他になんかあったろ・・。

【mail】php/IMAPでGoogleMailにアクセス失敗

sc20120517182214phpのnet_pop3(Pear)ではうまい事操作できなかったので、いっそモジュールのPHP_IMAPを利用してみました。

XAMPPでは既に利用できる状態だったので、そのままコードを書けます。

IMAPアクセスのサンプルはそこいら中にあるので割愛しますが、自分がやりたかったのが、IMAPディレクトリ(っていうのか?)へのアクセスです。

Googleメールでは、ラベルとか言われてます(イマイチ使いこなしてない事に気づきますw)

$this->mailbox
    ='{‘.$this->params[‘host’].’:’.$this->params[‘port’].’/ssl}INBOX’;

こんな感じで接続子を記述しますが、はてさてINBOX内ディレクトリにはどないしてアクセスするんでしょう。

ディレクトリというからには、"/"とか"."とかが想像付きますが、どないしてもエラー。

INBOX/スパム

日本語がダメなら、MIMEやらJISやらエンコードしまくってみます。それでもダメ(;´Д`)

もうメンドイので、英語表記に設定変更。これなら、エラーも出ずにアクセスできましたが、ぐぐってもなかなか解決できるネタが見つからない。できるはずなんだけど。。

sc20120517183232んで、これをサーバ上で稼働させようと、まずはPHP_IMAPのインスコです。

yum install php-imap

・・が、コンフリクトして一向に入ってくれない。

以前、適当にRPMやらでインストールしまくった結果がこれか。。ちゃんと管理してないとこうなる。

php-commonのバージョンがなんたらと言われてるが、怖くて削除できないし・・、困った。

VPSも移行準備してるので、余計な事したくないんですよね。