「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も移行準備してるので、余計な事したくないんですよね。

【mail】GoogleAppsにPOP3アクセス方法忘備録

sc20120513041739

GoogleAppsに自ドメインでメールを管理してもらってますが、POP3でアクセスできんのかな?と

IMAPでなんの不自由ありませんが、試しただけです。

と軽い気持ちでやってみたら何をやろうとエラーになってまう。

Googleメール設定で、POP3を有効にしたし、POPサーバやポート、認証方法全てを試してもアウト。

Googleヘルプに、こんな一文を発見して、「もしや・・」と(;´Д`)

「メールをサーバに残す等の設定をしてもスルー・・すんで、よろぴこ」

sc20120513042616確かにGoogleメール設定画面に、普通ならクライントで設定するメール残すうんぬん項目があるよ。んで、クライアント側で、メール残すうんぬん設定をOFFにしたら・・

やっとつながった(´・ω・`)

PHP(pear::net_pop3)からメールを確認しようとか、遊びのつもりが、時間がかかってしまったのお話です。

【PHP】Xamppのサーバが起動しない理由その2

sc20120210223117

ちょうどいまPC環境を新しくしているところで、偶然見つけたXAMPPのサーバ起動しない問題回避方法です。

よく遭遇しますよねぇ。これ(;^ω^)

ポート80がSkypeやIISなんかで使用されていて起動できないってのは良く聞きますが、そんなんじゃないぞ!という方向けの情報です。

PHP開発者なら、IDE環境としてEclipseを使用されている方が多いはずです。しかも、日本語化されていて全部入りのEclipseのMergeDoc Projectじゃないでしょうか?

このEclipseパッケのPHPを選択するとXamppももれなく付いてきますよね。

もち、私もこのXamppをそのまま利用してます。

MergeDocのEclipseを解凍した状態のディレクトリをそのまま利用すると、Xamppのサーバが起動しません。これに気づくのに結構時間がかかった(;^ω^)

ポート開けてもApacheが動かないだけでなく、MySQLも動かなかった点でなんとか気づいたんですけどね。

Windows移植系の例のごとく、ファイルパス関連の問題です。

ちゃんと、EclipseとXamppを別個にコピーするか、解凍状態のフォルダー名を適正にリネームすると動きますよ。お試しあれぇ~( ´∀`)

【soft】もしもエクスポーターの更新 Ver1.0.1

sc20120125203342

前エントリーで述べた機能の追加のデバックが完了しましたので、本日アップデートしました。

バグ直しやドキュメント整備と、結構改変部分が大きかったので、0.0.1だけバージョンを上げました。

また、EC-CUBEを利用する際に、1点だけデータベースを変更する必要があるのですが、こちらは管理画面から変更できず、初心者には厳しい点だったという事で、専用のPHPスクリプトを配布します。

dtb_csvテーブルを更新するものです。

どうぞ、よろしくお願いします。

もしもドロップシッピングエクスポーター for EC-CUBE
http://www.vector.co.jp/soft/winnt/business/se495163.html

ベクターの「ビジネス>販売・在庫・仕入れ管理」で公開してますが、人気順で見てみると、公開2日目で、150位辺り(全649本中)にいます。

【PHP】PHPの粋な関数shuffle()

sc20111217195800別にエントリーする程の話題じゃないんですが。気になったので。

いままで色々な言語を触ってきましたが、こんな関数が用意されてるのはPHP位じゃないかと思います。

bool shuffle(array &$array)

です。

もう、見たまんまで、配列の中身をシャッフルするだけです。しかも、戻値がBOOLからも分かるように、問答無用でシャッフルしてくれます。

もちろん、戻値はエラーかどうか?なんですが、失敗する事ないでしょうしね(ちなみに、乱数は内部でちゃんと生成しているそうです)

BASICにだってないでしょ。これw

業務用開発には無用な関数ですが、頭の片隅にでも置いておくといいでしょう。

PHPマニュアル
http://php.net/manual/ja/function.shuffle.php

【開発】PHPの便利なarray_multisortとか

sc20111203201802

最初に言っておきますが、自分はあまりPHPとかライトウェイト言語を信用しきってないタイプです(でも、Perlだけは特別だったり・・?)

なので、PHP言語仕様を完全に理解してません

んで、オブジェクト志向とはかけ離れた、便利な関数群が大量に利用可能なPHPで、とても優秀な配列ソート関数があったのでご紹介。


SQLなら一発なんだけどな・・とお嘆きの方に、CSVファイルなんかを、手っ取り早くソートしたい時とかにかなり便利なのが、array_multisortです。

列でソート、しかも2重3重に優先ソート処理も掛けられます。

しかし、残念な事に、マニュアル(ヘルプ)を見てもイマイチ分からないんです。ググっても、なんか良く分からない。これも、多機能であるが所以のシロモノのようです。

書き方は、

array_multisort(ソートネタ配列,ソート順とか,対象配列);

戻り値は、エラーtrue/falseです(他にも書き方はあるが、割愛)赤字の部分は、いくらでも続けて書ける多項関数です。

見て分かるように、IN/OUTが同じ変数になってしまいます。

理解するととても単純な関数なんです。ソートネタ配列には、対象配列と同じ数の要素が必用で、これを元に、対象配列を並べ替えをやってるだけなんです。

SORT_ASC – 昇順にソート
SORT_DESC – 降順にソート
SORT_REGULAR – 普通に比較
SORT_NUMERIC – 数値的に比較
SORT_STRING – 文字列として比較

ソート順指定には、上記のものを必要なだけ、引数として与えます。OR論理和とかじゃなく、普通に引数を連続で渡します・・・(PHPの仕様って変なの多いなぁ・・・)

sc20111203203329

 


具体的には、こんな感じになります。SQLっぽいでしょ。・・・そうか?(;^ω^)

$s_itemsが、処理対象の配列。$sort_***は、ネタ配列で、$s_itemsの列の値が入ってるだけです(ソートのネタだけなので、別に列の値じゃなくてもいいんですけどね)

ご察しのように、ネタ配列のインデックスが重要(≒処理対象のインデックス)なので、それだけ注意。普通は、列の値をそのまま入れるので問題ないでしょうけど(SQLでいうサブクエリや計算値のようなものを利用したければ、計算した結果を、そのインデックスに入れれば良い)

sc20111203204007

ネタ配列は、こんな感じで入れればいいんじゃないだろうか(CSVのファイルの例/タブ区切)

ちなみに、計算結果でソートしようとしてます。

PHPって未だに、(.Netとかと比べるのは厳しいと思うが)、あまりスマートじゃないですよね。

Perlに比べれば、多機能過ぎるので、ちょいちょいコマンド書くのに便利だが(Perl正規表現書けるし)、本気のソフトを書く気になれない。