プロが教える店舗&オフィスのセキュリティ対策術

Pealで書かれたメール送信フォーム(添付ファイル送信機能付き)から大きめの添付ファイルを送信したら、「ページを表示できません。」というエラーページか、有効期限切れページになってしまいます。
ただし、送信先にメールと添付ファイルはちゃんと送られています。
小さめのファイルであれば、問題なく送信後の送信済み画面に切り替わります。

Pealのソースを見ているのですが、待機時間を持っているようなところが見当たりません。
どのくらいまでのファイルサイズを許可するかを指定するところはあるので、そこには大きめのサイズを指定しています。

どのあたりを探れば、改善できそうですか?
お分かりになる方がいらっしゃいましたら、お教え下さいませ。

A 回答 (5件)

> “Internal Server Error”が表示されてしまいました。



それでは何が悪いのか分かりません。構文エラーでないことは確認しましたか?後はサーバーのエラーログを見るとか、use CGI::Carp 'fatalsToBrowser'; するなどして原因を特定して下さい。

また、改良後のスクリプトを見ると「送信済み画面」の出力部分がないのですが、もしかすると sendmail の中だったりしますか?名前からするに「メールの送信だけを行う関数」かと思っていたのですが・・・
もしそうならメール関連の部分(添付ファイルの処理を含むメールの生成から送信まで)だけを別関数にして、そこを子プロセスに実行させるようにして下さい。画面出力は全て親プロセスの仕事になります。

それと、スクリプト中の「# 何らかのエラー処理を書く」の部分には &error("子プロセスの生成に失敗しました"); などと書いて下さい。単にコピーしただけではダメです。

# ちなみに、No.4 の回答内のスクリプトをそのままコピーしたってことはないですよね?見やすさのためにインデントに全角空白で書いているので、それをタブまたは半角空白に置換しないと構文エラーになります。
    • good
    • 0
この回答へのお礼

まず、「送信後の画面表示」出力部分も sendmail の中でした。
そして、一部、全角空白が入っていたせいもありました。
失礼いたしました。

よって、
・テキスト情報送信準備
・添付ファイル送信準備
・メール送信
を子プロセスに入れて、

・送信情報保存ファイル書込み
・送信後の画面表示
は、親プロセスのままにしました。

そして、実行すると、見事上手くいきました。
添付ファイルを付けても、すぐ送信後の画面表示がされ、送信済みとなります。
しかし、10MB近くの大きいファイルを添付すると、ファイルサイズが0で送信されてしまうこともありました。(上手く送信されていることもあった)
ただ、目的はほぼ達成できましたので、これで行こうと思います。

今回は勉強にもなりました。
どうもありがとうございました。

お礼日時:2005/07/04 07:25

CGIで重い処理をする場合、その処理を子プロセスに任せてしまう、というのも手です。



sendmailという関数が重いのなら、その呼び出し部分を
  &sendmail;
から、
  my $pid = fork;
  if (!defined $pid) {  # fork失敗
    # 何らかのエラー処理を書く
  }
  elsif (!$pid) {      # 子プロセス
    # ブラウザとの通信と関わりを断つ
    close STDOUT;
    close STDERR;
    # 重い処理
    &sendmail;
    exit;
  }
のような感じに変えます。

親プロセスは子プロセスの終了を待ちませんが、問題はありません。
この方法は変数の引継ぎなどの問題で単純にスクリプトを切り離せない場合にも有効です。
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。
まさに単純に切り出せないで困っておりました。
ただ、メイン処理では「&sendmail();」しか呼んでないんです。
sendmail関数の中で添付ファイルをアップロードしているサブルーチンを呼んでいるのですが、
そのサブルーチンで時間がかかっているのかもしれません。

ちなみに、ご教授いただいた内容を元にスクリプトに手を加えて実行してみましたが、
“Internal Server Error”が表示されてしまいました。
コードの書き方が間違っているのでしょうか?
以下のように修正しました。

### メイン処理(改良前)
&decode();
if ($in{'mode_sys'} eq 'send') {
 &sendmail();
}
&error("不正なアクセスです");


### メイン処理(改良後)
&decode();
if ($in{'mode_sys'} eq 'send') {
 my $pid = fork;
 if (!defined $pid) { # fork失敗
  # 何らかのエラー処理を書く
 }
 elsif (!$pid) {  # 子プロセス
  # ブラウザとの通信と関わりを断つ
  close STDOUT;
  close STDERR;
  # 重い処理
  &sendmail;
  exit;
 }
}
&error("不正なアクセスです");

お礼日時:2005/06/30 15:28

この場合、cgiではなくシェルスクリプトとして実行する訳ですから、拡張子はplなどの方が良いのではないですか?拡張子付けのルールをどうしているかにもよりますが。



&はシェルで「バックグラウンドで実行」の意味です。コマンドの末尾につけます。コマンドラインからコマンド名を入力して実行する時に&を末尾に付ける事で、バックグラウンドで実行され制御がすぐコマンドラインに戻ってきます。この同じ動作をSYSTEM関数で行うという事です。&はコマンド文字列の末尾、つまり""の中に付けて下さい。

実はperlではこういう事した事ないのですが、phpでできるので同じじゃないかな、と思います。
    • good
    • 0
この回答へのお礼

ありがとうございました。
ただ、切り出す処理の中でサブルーチンを呼んでいたりしてるので、
単純に切り出せなくて困ってしまいました。

お礼日時:2005/06/30 15:20

非同期処理といっても大した事はなくて、時間の掛かるプロセスを別なスクリプトで書いて、system関数などで呼び出すというものです。

この時、コマンドの末尾に"&"を付けるとバックグラウンド実行となって制御がすぐ戻ってきます。
    • good
    • 0
この回答へのお礼

ありがとうございます。
Pealのコードを見るに、どうやら

  sub sendmail {
  ・・・}

のメール送信部分で時間がかかっていると思われるので、

  sub sendmail {
  ・・・}

部分を、別のファイル(xxx.cgi)に切り出しました。
そのファイル(xxx.cgi)を、system関数で呼んで実行させたいのですが、
記述は「system("xxx.cgi");」でよろしいのでしょうか?
コマンドの末尾に"&"を付けるというのは、具体的にどこに付けるのでしょうか?
「system&("xxx.cgi");」でしょうか?
それとも「system("xxx.cgi"&);」もしくは「system("xxx.cgi")&;」
でしょうか?

お礼日時:2005/06/30 13:41

ブラウザがタイムアウトしてしまったのではないでしょうか。



ブラウザはリクエストを送ったサーバーから一定時間返答が何も無ければ「タイムアウトエラー」と判断してエラーページを表示します。その画面でリロードなどを行えば「有効期限切れエラー」が表示されるはずです。サーバー側では、ブラウザがタイムアウトをしたなんて情報を得る事はできないので、処理は続行します。そのため、メールは送られるがブラウザでエラーが出るという現象になっているのだと思います。

タイムアウトまでの時間は個々のクライアントの設定によるところなので、スクリプトで変更する事はできません。回避するとしたらスクリプトの構造を変えて時間の掛かる処理を非同期(処理の終了をスクリプト側で待たない)方法で行うか、細々とブラウザに対して画面の出力を行って、ブラウザがタイムアウトしないようにするしかありません。
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。
まさにそうだと思います!そんな感じの動きです。
ちなみに、Pealの非同期処理とは、どんなものがありますか?
CやVB.NETでは、ちょっとスレッド処理とかやったことはありますが、Pealではないので・・・
非同期部分を、別のスクリプト(PHPなど)で書いた方がいいですかね?
もし、ご存知であれば、アドバイス下さいませ。

お礼日時:2005/06/29 20:58

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!