2010年6月アーカイブ

私はDocomoの携帯しか持ってないので、事前にauとsoftbankを持ってる友人に頼んで、メールヘッダなどを調査したらこんな感じ↓

■ Docomo
----------------------------------------------------------------------------------
From ****@docomo.ne.jp Wed May 26 17:54:11 2010
Return-Path: <****@docomo.ne.jp>
X-Original-To: ***@igreks.jp
Delivered-To: ***@igreks.jp
Received: from localhost (localhost.localdomain [127.0.0.1])
by ***.igreks.jp (Postfix) with ESMTP id 5DE338B41B2
for <***@igreks.jp>; Wed, 26 May 2010 17:54:11 +0900 (JST)
X-Virus-Scanned: amavisd-new at igreks.jp
Received: from ***.igreks.jp ([127.0.0.1])
by localhost (igreks.jp [127.0.0.1]) (amavisd-new, port ****)
with ESMTP id kkpANBxiUasa for <****@igreks.jp>;
Wed, 26 May 2010 17:54:11 +0900 (JST)
Received: from docomo.ne.jp (mail108.docomo.ne.jp [203.138.203.8])
by ***.igreks.jp (Postfix) with ESMTP id 3E6618B40B0
for <***@igreks.jp>; Wed, 26 May 2010 17:54:11 +0900 (JST)
Date: Wed, 26 May 2010 17:54:09 +0900 (JST)
From: ****@docomo.ne.jp
To: ***@igreks.jp
Subject: =?iso-2022-jp?B?GyRCMSsbKEI=?=
Message-ID:
MIME-Version: 1.0
Content-Type: text/plain; charset="iso-2022-jp"
Content-Transfer-Encoding: 7bit

$BK\J8(B
----------------------------------------------------------------------------------


■ au
----------------------------------------------------------------------------------
From ****@ezweb.ne.jp Wed May 26 18:24:29 2010
Return-Path: <****@ezweb.ne.jp>
X-Original-To: ***@igreks.jp
Delivered-To: ***@igreks.jp
Received: from localhost (localhost.localdomain [127.0.0.1])
by ***.igreks.jp (Postfix) with ESMTP id F1F818B41B2
for <***@igreks.jp>; Wed, 26 May 2010 18:24:28 +0900 (JST)
X-Virus-Scanned: amavisd-new at igreks.jp
Received: from ***.igreks.jp ([127.0.0.1])
by localhost (igreks.jp [127.0.0.1]) (amavisd-new, port ****)
with ESMTP id CBSY6-Rv+mf6 for <***@igreks.jp>;
Wed, 26 May 2010 18:24:28 +0900 (JST)
Received: from ezweb.ne.jp (nx3oBP07-06.ezweb.ne.jp [59.135.39.240])
by ***.igreks.jp (Postfix) with ESMTP id D7FC88B40B0
for <***@igreks.jp>; Wed, 26 May 2010 18:24:28 +0900 (JST)
Received: from nxev04mp06 (localhost [127.0.0.1])
by nxev04mp06.ezweb.ne.jp (EZweb Mail) with SMTP id 955ED5BC640B4
for <***@igreks.jp>; Wed, 26 May 2010 18:24:28 +0900 (JST)
From: ****@ezweb.ne.jp
To: ***@igreks.jp
Subject: =?iso-2022-jp?B?GyRCMSsbKEI=?=
Message-ID: <2010052618242860697200007c12@nxev04mp06.ezweb.ne.jp>
Date: Wed, 26 May 2010 18:24:28 +0900
Mime-Version: 1.0
Content-Type: text/plain; charset="iso-2022-jp"
Content-Transfer-Encoding: 7bit

$B%6!<%6!<(B
----------------------------------------------------------------------------------


■ Softbank
----------------------------------------------------------------------------------
From ****@softbank.ne.jp Wed May 26 18:24:36 2010
Return-Path: <****@softbank.ne.jp>
X-Original-To: ***@igreks.jp
Delivered-To: ***@igreks.jp
Received: from localhost (localhost.localdomain [127.0.0.1])
by ***.igreks.jp (Postfix) with ESMTP id 975BD8B41B2
for <***@igreks.jp>; Wed, 26 May 2010 18:24:36 +0900 (JST)
X-Virus-Scanned: amavisd-new at igreks.jp
Received: from ***.igreks.jp ([127.0.0.1])
by localhost (igreks.jp [127.0.0.1]) (amavisd-new, port ****)
with ESMTP id HQrmiDMGcT3n for <***@igreks.jp>;
Wed, 26 May 2010 18:24:36 +0900 (JST)
Received: from mmrts049p01c.softbank.ne.jp (mmrts049p01c.softbank.ne.jp [123.108.236.27])
by ***.igreks.jp (Postfix) with SMTP id 6D9898B40B0
for <***@igreks.jp>; Wed, 26 May 2010 18:24:36 +0900 (JST)
Subject: =?ISO-2022-JP?B?GyRCJCYkcyQzGyhC?=
Mime-Version: 1.0
Content-Type:text/plain;charset=ISO-2022-JP
Content-Transfer-Encoding:7bit
Date: Wed, 26 May 2010 18:24:35 +0900
Message-ID: <20100526182435672870.2aea@0016E68F5982>
From: <****@softbank.ne.jp>
To: ***@igreks.jp
Sender:****@softbank.ne.jp
X-Priority: 3

$B%b%j%b%j(B
----------------------------------------------------------------------------------


仕様としては、

・DBはMySQL
・空メの送信先は「reg_kara_mail@igreks.jp」とする
・空メの件名に名前を指定できる。
・登録済みの場合はエラーメールを返す。
・空メ本文にメルマガIDをあらかじめ記載しておく。
・メルマガIDが認識できない場合もエラーメールを返す。
・読者データテーブル名は仮に「user_'メルマガID'」、文字コードはUTF8とする。

これを受けて、スクリプトはざっとこんな感じに。
※おおまかな流れだけで、細かい点は割愛してます


■ 空メール登録処理用CGI(karame.cgi)
-----------------------------------------------------------------------------------
#!/usr/bin/perl

package main;

use strict;
use CGI;
use DBI;
use Unicode::Japanese;

require './lib/get.pl'; #各種データ取得用ライブラリ(詳細割愛)
require './lib/proc.pl'; #各種処理用ライブラリ(詳細割愛)
require './lib/db.pl'; #DB接続、各種SQL実行用ライブラリ(詳細割愛)
require './lib/start.pl'; #メール配信用ライブラリ(詳細割愛)

&db::open(); #DB接続

my $sys_msg = ''; #エラー返信用メッセージ
my ($email, $name, $id);

###### メールから標準入力をパース
my $grep = '[\d\w-.+]+\@[\d\w-]+(\.[\d\w-]+)+'; #メールアドレスの正規表現

while(<>){
 if($_ =~ /^From.*?($grep)/i || $_ =~ /^Return-Path:.*?<($grep)>/i){
  $email = $1; #メールアドレス
 }
 if($_ =~ /^Subject:\s*(.+)$/i){
  $name .= $1; #名前
 }
 if($_ =~ /^\s*(=\?ISO-2022-JP.+\?=)\s*$/i){ #件名が途中で改行されてる時のため
  $name .= $1;
 }
 if($_ =~ /^mid:(.+)$/){
  $id = $1; #メルマガID
 }
}
if($email){
 if($id){
  my $stg = &get::setting_data($id); #メルマガ設定データ取得
  if($stg){
  ####### 読者テーブル内重複チェック
  &db::query("
   SELECT * FROM user_$id WHERE email='$email'
  ");
  my $href = $db::sth->fetchrow_hashref();
  if($href){
   #すでに登録済みの場合
   $sys_msg = <<EOM;
    送信いただいたメールアドレス「$email」はすでに登録済みです。
    このまま次回の配信をお待ちください。
EOM
   $sys_msg =~ s/\t//g;
   #メール返信処理
   &start::return_mail(
    '空メール登録処理エラー',
    $sys_msg,
   );
   exit;
  }
  if($name){
   #名前の入力があった場合
   $name = Unicode::Japanese->new(
    &proc::base64decode($name), #Base64デコード処理
    'jis'
   )->utf8; #JISからUTF8に変換
  }
  ######## 新規登録
  &db::query("
   INSERT IGNORE INTO user_$$pd{'id'} (
    no,  #オートインクリメント
    email,
    name,
    ・
    ・
    ・
   )
   VALUES(
    '',
    '$email',
    '$name',
    ・
    ・
    ・
   )
  ");
 }
 else{
  $sys_msg = <<EOM;
   登録しようとしたメールマガジンは存在しないか、すでに廃刊されています。
   お手数ですが、詳しくは発行者までお問い合わせください。
EOM
 }
}
else{
 $sys_msg = <<EOM;
  送信いただいた情報に不備があり登録できませんでした。
  空メール本文の内容は変更せずに送信してください。
  何度もこのエラーメールが返信される場合は、お手数ですが発行者までお問い合わせください。
EOM
}

########## エラー返信処理
if($sys_msg){
 &start::return_mail(
  '空メール登録処理エラー',
  $sys_msg,
 );
}
&db::close(); #DB切断

exit;

-----------------------------------------------------------------------------------



■Postfixエイリアス設定ファイル(/etc/aliase)に以下を追加
-----------------------------------------------------------------------------------
reg_kara_mail:  "|cd 'karame.cgiがあるディレクトリの絶対パス'; ./karame.cgi"
-----------------------------------------------------------------------------------

■リスタート
-----------------------------------------------------------------------------------
# newaliases

# /etc/init.d/postfix restart
-----------------------------------------------------------------------------------


■以下のようなメールを「reg_kara_mail@igreks.jp」宛に送る

 件名:自分の名前もしくは空白
 本文:mid:melmagaID

以上。


※レンタルサーバなどでエイリアスが設定できない場合は、後からcronなどでPOPアクセスして処理するなどの方法もある。(参考→http://www.igreks.jp/dev/2009/06/pop.html
この場合は返信メールが即時配信されない。


※ディズニーモバイルとかwilcomは調べてないけど、まあだいたい同じだべってことで。
メールの件名だけのためにMIME::Base64とか使いたくないなーと思ったので。

ほぼ、こちら(http://nabe.blog.abk.nu/064)の丸写しでごめんなさい。


-----------------------------------------------------------------------

#エンコード

my $subject1 = &base64_Encode($target1);

#デコード

my $subject2 = &base64_Decode($target2);



sub base64_Encode {
my ($target) = @_;
my ($base) = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
."abcdefghijklmnopqrstuvwxyz"
."0123456789+/";
my $eStr = "";
my $pStr = unpack("B*",$target);
for(my $i = 0;my $cStr = substr($pStr,$i,6); $i += 6){
$eStr .= substr($base,ord(pack("B*","00".$cStr)),1);
if(length($cStr) == 2){
$eStr .= "==";
}
elsif(length($cStr) == 4){
$eStr .= "=";
}
}
return("=?ISO-2022-JP?B?$eStr?=");
}

sub base64_Decode {
my ($str) = @_;
$str =~ s/=\?ISO-2022-JP\?B\?([A-Za-z0-9\+\/=]*)\?=/{&base64_Decode2($1)}/egi;
return $str;
}
sub base64_Decode2 {
my ($str) = @_;
my @base64ary = (
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, # 0x00〜0x1f
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, # 0x10〜0x1f
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,62, 0, 0, 0,63, # 0x20〜0x2f
52,53,54,55, 56,57,58,59, 60,61, 0, 0, 0, 0, 0, 0, # 0x30〜0x3f
0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14, # 0x40〜0x4f
15,16,17,18, 19,20,21,22, 23,24,25, 0, 0, 0, 0, 0, # 0x50〜0x5f
0,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40, # 0x60〜0x6f
41,42,43,44, 45,46,47,48, 49,50,51, 0, 0, 0, 0, 0 # 0x70〜0x7f
);
my $ret;
my $buf;
my $f;
if (substr($str, -1) eq '=') { $f=1; }
if (substr($str, -2) eq '==') { $f=2; }
for(my $i=0; $i<length($str); $i+=4){
$buf = ($buf<<6) + $base64ary[ ord(substr($str,$i ,1)) ];
$buf = ($buf<<6) + $base64ary[ ord(substr($str,$i+1,1)) ];
$buf = ($buf<<6) + $base64ary[ ord(substr($str,$i+2,1)) ];
$buf = ($buf<<6) + $base64ary[ ord(substr($str,$i+3,1)) ];
$ret .= chr(($buf & 0xff0000)>>16) . chr(($buf & 0xff00)>>8) . chr($buf & 0xff);
}
if ($f>0) { chop($ret); }
if ($f>1) { chop($ret); }
return $ret;
}

-----------------------------------------------------------------------
結論から言うと、親プロセスの「wait;」の直後にもう一度MySQL接続処理を呼ぶ。
※2010/7/23追記:さらに各プロセスの頭でMySQL接続処理を呼ぶ。
ただそれだけ。


■MySQL接続用(db.pl)
--------------------------------------------------------------------------
package db;

use strict;

sub open{
my $dbs = "DBI:mysql:$dbname:$dbhost";
our $dbh = DBI->connect($dbs,$dbuser,$dbpass);
if(!$dbh){ die 'MySQL connection error!'; }
}

sub query{
my ($sql) = @_;
our $sth = $db::dbh->prepare($sql) || die $db::dbh->errstr();
my $exec = $sth->execute() || die $sth->errstr();
return $exec;
}

sub close{
$db::sth->finish();
$db::dbh->disconnect();
}

1;
--------------------------------------------------------------------------


■よくあるforkの処理
--------------------------------------------------------------------------
#!/usr/bin/perl

use strict;
use DBI;

require 'db.pl'; ######## 上のファイル読み込み
&db::open(); ######### 最初のMySQL接続

(親プロセス処理)

my $pid;
FORK: {
 if($pid = fork) {
  &db::open(); ###### ←【ここで単発接続】
  (親プロセス処理)

  close(STDOUT);
  wait;
  &db::open();  ###### ←【ここで再接続】これはfork終了後の処理用
 }
 elsif (defined $pid) {
  &db::open(); ###### ←【ここで単発接続】
  close(STDOUT);

  (子プロセス処理)

  exitしなくても勝手にexitされる?
 }
 elsif($! =~ /No more process/){
  sleep 5;
  redo FORK;
 }
 else{
  die 'Fork is not supported!';
 }
} # End Of Label:FORK


(親プロセス処理再開)

&db::close(); ######### 正規のMySQL接続切断
exit;
--------------------------------------------------------------------------



今まで、子プロセス内処理が終われば、全体の処理も終わるような構造のスクリプトばっかりだったので、なかなか気づかなかった。
ログも「mysql server has gone away...」ってしか出ないし。
標準出力を切ってるからブラウザからのデバックだけだと気がつかず、メルマガの空メール処理実装しようとして初めて気がついた。

一般的には、子プロセス内に入ったら、改めて子プロセス専用のコネクションを作らないと、子プロセスの終了時にMySQLコネクションが切断されてしまうらしい。
(つまり、親と同じコネクションを使っていると、親のコネクションも切れる)
全然しらんかった。


でも、なぜか子プロセスの最初で「&db::open();」してもダメだった。
perlのforkは親の変数が子に全部コピーされるから(同じデータベースハンドル、またはステートメントハンドルを使っている)なのかな?


わざわざ、子プロセス専用のSQL発行サブルーチン作るのも非効率だし、どうしようかなと悩んだ挙句こうなった。


時々、MilkyStepで即時配信メールが送れなくなるのはコレのせいだったりして。


※2010/7/23追記:
子プロセスの処理中に親プロセスが終了しても、子プロセスのMySQL接続が切れる。
また、親が終了する前に子のプロセスIDを使い始めると親のMySQL接続が切れる。
原因はよくわからんが、親・子それぞれの頭で接続処理を単発で入れたら上手く行った。
clamav0.96をインストールした先々月くらいから、毎日のclamav起動時にいっぱいエラーが出てた。

最初は面倒くさいので無視してたが、cronのこのメールのせいでサンダーバードまで重くなってきたので何とかしてみよう。


LibClamAV Warning: cli_scanbzip: bzip2 support not compiled in とか
LibClamAV Warning: pread fail: page 0 pages 1... とか
なんかいっぱい出てるので、まず最初の行から。

えー、bzipがサポートされてませんよと・・・

じゃあインストールすればいいんだべってことで

# yum install bzip2

しかし、

# すでにインストール済みです・・・



というわけで、ここはあきらめて(早っ)clamavのconfigure,make,make installだけしなおして次へ。


pread fail のエラーの情報はググると見つかるものの、とりあえずみんなpread処理を回避して対処してるみたいなので、私もそうしよう。

というわけで、「/etc/cron.daily/clamav」を以下の用に変更。

-----------------------------------------------------------------------------------------------------------
/usr/bin/clamscan -r --quiet --log=/var/log/clamav.log --move=/var/infected_virus/

   ↓

/usr/bin/clamscan --exclude-dir=/sys -r --quiet --log=/var/log/clamav.log --move=/var/infected_virus/
-----------------------------------------------------------------------------------------------------------



では、明日起きてからのお楽しみ。

このアーカイブについて

このページには、2010年6月に書かれたブログ記事が新しい順に公開されています。

前のアーカイブは2010年4月です。

次のアーカイブは2010年7月です。

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。

ウェブページ

Powered by Movable Type 4.22-ja