プロバイダ:VC-NET スクリプト:Perl

在庫管理などで、在庫を変更中に変更前の値を第三者が閲覧してしまうと矛盾がおきますよね?そこで質問なのですがこの様な場合みなさんどうされてるのですか?


私は、書き換えるファイルを

file → file986172208

アクセスした時間(Perlのtime)を付加してファイルロックをして、
書き込みを終えれば

file986172208 → file

また元に戻す。


イントラネット上では期待した結果が得られたのですが、いざアップしたら
”サーバー側のエラーですよ”と表示されました。
ですがTELNETから動作させるとうまく動作しました。
ファイルのパーミションは

スクリプトファイル:755 データファイル:666 です。

みなさんからのご意見お待ちしています。

このQ&Aに関連する最新のQ&A

A 回答 (4件)

まず、イントラネット上で動作したというのは、どういうふうに実


行させたら動作したという意味でしょうか?それは、ローカルな
WEBサーバー経由の cgi として動作したのか、telnet で動作させ
たのと同レベルなのかですが。

あと、どういうエラーが起きたのかは、わからないのでしょうか?
スクリプトの各段階で、どこまで進んだか、どういう状況かを、適
当なファイルにログとして残して行って、解析した方がいいと思い
ます。そのファイルさえ作成されないのであれば、スクリプトの起
動もできてないのかもしれませんし。

それから、ロックの方法としては、ファイル名の rename で行って
いるということですね?rename に失敗したら、ロック失敗という
方式でしょうか?原理的には正しくロックできる方法だと思います。

# もっとも、時刻を付加しなくても、共通のファイル名を使っても
# 大丈夫なはずです。もしそれでだめだとすると、時刻を付加して
# も1秒以内に複数のアクセスがあると破綻しますから。

ただ、何かの原因で更新中に file という名前のファイルが作成さ
れないことと、更新中にそのスクリプトが死なないことが保証でき
なければいけません。前者が起きると多重のアクセスが生じますし、
後者が起きるとデッドロックになります。

unix のサーバーで perl を使い、そのサーバー内のプロセス同士
でロックするのなら、flock を使うのが確実だと思います。
man perlfunc で flock の項目に使用例もあるので、見てください。

この回答への補足

さっそくのご回答ありがとうございます m(_ _)m

イントラネット上で動作したというのは、ローカルでWEBサーバーをたてて、
そこからCGI経由で動作したということです。
サーバー:httpd 1.27c(フリーウェア)

それから初歩的なことなのですがエラーログは自分で取れるものなのですか?
サーバー側が作ってくれるものだとばっかりおもってました。
だとしたらどのようにすればいいのでしょうか?(次から次へと質問が…)

flockはファイルをオープンしたりライトする際に有効なんですよね?
データをユーザーが入力してる間はずーーとロック状態でないとまずいんですよ。

”いま100個あったのに発注かけたら0個だと!?どうなってるんだ”とか…


ロック方法は、ファイル名の rename で行っています!
参考:http://www.din.or.jp/~ohzaki/perl.htm#File_Lock

今回が初めての投稿なので、何分的確に質問できていませんがもう少しお付き合いください。宜しくお願い致します。

補足日時:2001/04/06 12:16
    • good
    • 0

パーミッションについて:



httpd の設定にもよりますが、~daresore にある cgi を実行した
場合には、daresore の権限にするのが普通ですから、本人が読み
書きできるなら cgi プログラムにもできると考えてもいいかと思
います。でないと、自分のディレクトリのファイルが他人の cgi
プログラムからアクセスできることになります。もっとも、それが
確かかどうかは、ログをちゃんと調べる必要があります。

ログについて:

適当なログファイルを
open(STDERR, ">/tmp/logfile");
のようにオープンして、自分で
print STDERR ...;
していけばいいだけのことです。ログを作るにもパーミッションの
問題がからむと面倒なので、/tmp か /var/tmp の使用が許されて
いるなら、とりあえずはそこに作るのがいいでしょう。どういう権
限で動いているかは、そのログファイルのオーナーが自分かどうか
で調べられます。

で、目的のファイルが rename に失敗したり、open できなかった
ら、
die "$!"; か warn "$!";
しておきましょう。

ロックの方法について:

一般論として、長時間ロックをするのはよくありません。
「いま100個あったのに発注かけたら0個だと!?どうなってるんだ」
の問題は、顧客が発注するのが遅かったせいにすればいいのです。
でないと、100個あったことは確認したけど、発注せずにいきなり
接続を切ったりしてしまったらどうなりますか?cgi プロセスがそ
のことに気付いて、ファイル名を戻すまでは、他の顧客は100個あ
ることすら確認できなくなりますよ。
    • good
    • 0
この回答へのお礼

返事が送れて申し訳ございません。
エラーログの作成うまくいきました!これからはこのようなエラーは
ログから探っていきます。お忙しいところ本当にありがとうございました。
また今度はデッドロックしても定期的にチェックするプログラムなんかも作成したいですね。これからも何卒宜しくお願いします。^^

お礼日時:2001/04/06 16:45

ファイル名のrenameを行うには、当該ファイルのあるディレクトリに対して書き込みを許可するPermissionが立っていないといけません。


今回の場合、sub_dirのPermissionが701になっているということですが、この場合nobodyはsub_dirに対する書き込み許可が与えられていませんので、renameに失敗しInternal Server Errorが出ていると思われます。

従って、sub_dirのPermissionを777にすれば予定通りの動作をすると思いますが。
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。m(_ _)m
サーバーのエラーが英語なのでついついめをそらしていましたが正しく”Internal Server Error”でした。

ちょっとしたスクリプトを書くときにCGI&Perlのポケットリファレンスを
読むのですが、記述されてました!!

”ファイルシステムを超えてファイル名を変更しようとすると通常失敗に終わります(プラットフォームに依存)。”

以前イントラネットで使用したOSはwindowsだったので意識してませんでしたがそれを意味していたなんて…。パーミション属性に書き込み許可があるのは分かっていましたがディレクトリにも同じことが言えるなんてホント新発見です(私だけ?)rename もまた然り、名前を 書・き・換・え・る ですね!

いやー、普段は過去ログをみてるだけでしたが投稿することでたった一日で解決するなんて。回答をしていただいたみなさんに感謝の気持ちでいっぱいです。

お礼日時:2001/04/06 17:02

ディレクトリのパーミッションがおかしいのでは?



補足
通常 *普通*の環境であれば、CGIの実行は、ログインアカウントではなく
nobadyなどの専用のユーザーで実行されます。

それではちゃんとしたロックはかけられないと思いますが
それは質問じゃないんですよね?

この回答への補足

またまた回答いただきありがとうございます。(^v^)
ご指摘を受けたディレクトリのパーミッションなのですが


public_html(ルートのディレクトリ):701
   |
   sub_dir(サブディレクトリ):701
     |
     file(変更したいファイル):666

                       です。

windowsユーザーにはパーミションたる概念がまったくないので、
ピンとこないのです、はい。

”ログインアカウントではなくnobadyなどの専用のユーザーで実行されます。 ”
”それではちゃんとしたロックはかけられない”

う~ん、難しいですね。ブラウザからアクセスすることが”nobadyなどの専用のユーザー”でアクセスしているということですかね?
変更するファイルのパーミッションを 666 で権限を与えてるとおもうのですが?

勉強になるHPなどありましたらご紹介ください。たびたびお手数をお掛けしますが宜しくお願い致します。

補足日時:2001/04/06 12:56
    • good
    • 0

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

このQ&Aと関連する良く見られている質問

QPerlをcshスクリプトに書きなおしたい

以下のPerlで書かれたCGIをcshスクリプトに書き直したく思っています。

#!/usr/local/bin/perl
# load libraries
require ("/usr/local/bin/cgi-lib.pl");
# cancel stdout buffering
$| = 1;
# header response
print "Content-type: text/html\n\n";
print STDOUT "<HTML><HEAD></HEAD><BODY>\n";
&ReadParse;
open(COMM, "|./message > ./message.out") || die;
$in_text = $in{"Name"};
print COMM "Name: $in_text\n";
...

"Name"という変数名で受け取った文字列を$in_textに代入している
ようですが、この辺りの処理、cshではどう書けばよいのでしょうか。

Aベストアンサー

perl 用のライブラリである cgi-lib.pl を読み込んで、その中のReadParse を使っているので、その結果としてグローバル変数%in に設定されているのを取り出しているのが$in{"Name"} です。
もし、perl を使用できないので全面的にcsh のみで書きたい、というのであれば、cgi-lib.pl が現在の形では使用できなくなるので、cgi-lib.pl で行っている処理を他のプログラムやスクリプト等で代替した上で、csh にはハッシュはないですから、関数等で実装する必要があると思います。

QCGI perlでこんなスクリプトをご存知ないでしょうか?

一覧表があって、そこに仮に5個の名前があるとします。

ログインして自分のデータを変更や訂正。
更新されると、一覧表の順序内において、
一番先頭に表示される。

これって一番近いのは、やっぱり掲示板なんでしょうか?
もしこれに近い、無料配布されているサンプルを
ご存知でしたら、お教えいただけませんか?

Aベストアンサー

基本は名簿管理…なのでしょうか?

以下のものはどうでしょうか、更新順に表示も可能です。

■Miniりすと
http://www.minicgi.net/cgi2/list.html

参考URL:http://www.minicgi.net/cgi2/list.html

QApachでCGI(Perlスクリプト使用)を動かすときに先頭の#!に関係なく実行できるようにするには。

ApachでCGI(Perlスクリプト使用)を動かすときに先頭の#!のPerlを動かす場所(?)を指定する行が無かった場合や、違う場合でも、Apachが勝手にperlの場所を解釈しスクリプトを実行してくれるようになるhttpd.confの設定方法ってありますか?

Aベストアンサー

> CGI(Perl使用)の部分もあるので、ローカルで実際に動かしてからサーバにアップしています。
> ローカルでの実行環境がApach(for win32)+ActivePerlで、サーバにアップするときにわざわざ#!部分を変更しなければなりません。それが少々めんどくさいので
> 質問したわけであります。

発想の転換をしてみてください。
要するに「she-bang 書き換えが面倒くさい」だけなんですよね?

Apache に依存させるのではなく、ActivePerl を入れなおして、ディレクトリをあわせてみてはいかがでしょうか。
ActivePerl をインストールする際に、例えばサーバ側が
/usr/bin/perl
だった場合、
c:\usr
フォルダを作っておいて、インストール先を c:\usr にしておけば、perl インタプリタの実行ファイルが c:\usr\bin\perl.exe になります。
she-bang を #!c:\usr\bin\perl とすればいいのは勿論なんですが、Apache を介せば、UNIX 表記でも問題ないので、#!/usr/bin/perl と記述することが可能です。当然それなら、いちいち書き換えなくても、サーバ側でそのまま利用することが可能です。

コツとしては、perl のパスの bin ディレクトリの上位まで、Windows 上に作っておいて、インストール先として、そこまで指定します。

/usr/local/bin/perl としたい場合は、c:\usr\local フォルダを作っておいて、インストール先として c:\usr\local を指定すれば、自然と bin ディレクトリが作られ、その中に perl.exe がインストールされます。
で、CGI として使用したいファイルの先頭を
#!/usr/local/bin/perl とすれば、サーバでも Win 環境でも共用できる she-bang が書けますので、そういうことを気にしなくてもいいと思います。
私はかれこれ 3 年間、この方法を使ってます。

> CGI(Perl使用)の部分もあるので、ローカルで実際に動かしてからサーバにアップしています。
> ローカルでの実行環境がApach(for win32)+ActivePerlで、サーバにアップするときにわざわざ#!部分を変更しなければなりません。それが少々めんどくさいので
> 質問したわけであります。

発想の転換をしてみてください。
要するに「she-bang 書き換えが面倒くさい」だけなんですよね?

Apache に依存させるのではなく、ActivePerl を入れなおして、ディレクトリをあわせてみてはいかがでしょうか。
A...続きを読む

QperlのMIMEモジュールの代用ができるスクリプトは?

CGIでメール受信処理をするために、Net::POP3の使用はできましたが、MIME系のモジュールがサーバーに用意されていないらしく、受信したメールの解析がうまくいきません。
モジュールなので、サーバーのPERLに管理者が追加しないといけないと思うのですが、お願いしても断られてしまいました。
jcode.plやcgi-lib.plのように、requireで読み込むようなパターンにしようと思うのですが、代用できるようなスクリプトをご存知の方はいらっしゃらないでしょうか?
MIME-Base64
MIME-tools
MailTools
IO-stringy
の四点に変わるものを探しています。

よろしくお願いいたします。

Aベストアンサー

動作未確認ですが、これでできるかもしれません。

http://hp.vector.co.jp/authors/VA022047/program/mail.txt

ご参考までに。

参考URL:http://hp.vector.co.jp/authors/VA022047/program/mail.txt

Qループが可能なHTMLテンプレートを切り離せるperlスクリプト

はじめまして、いつもphpをつかっててperlの知識がない者です。
perlの中にHTML部分を記入するとコードが読みにくくなるので別ファイル(テンプレート)として切り離したいのです。
そのとき、たとえば掲示板のように、ループ部分があっても、そのテンプレートがつかえるようにしたいのですが、そのような、スクリプトをご存知の方いらっしゃいましたら、どうか教えてください。
よろしくお願いいたします。

Aベストアンサー

Antsさんこんばんは。掲示板ソフトではそういう目的のために定番になっている手法があります。
モジュールがなくても大丈夫です。おそらくモジュールも同じようなことをやっているはずです。
例えば次のようなファイルをtemplate.htmlという名前で保存します
****************************************************

<html>
<head>
<title><!--title--></title>
<meta http-equiv="Content-Type" content="text/html; charset=<!--charset-->">
<meta http-equiv="Pragma" content="no-cache">
</head>

<body bgcolor="#<!--bgcolor-->" text="#<!--textcolor-->">
<h1><font color="#<!--fontcolor-->"><!--owner-->さんの掲示板</b></font></h1>
<!--begin-->番目から<!--end-->番目までの記事を表示しています<br>

<!--message-->

<hr>
<form action="BBS.cgi">
<input type="hidden" name="Next" value="<!--nextpage-->">
<input type="submit" value="次のページへ">
</form>
</body>
</html>

******************************************************************

そしてスクリプトの中で$title,$charset,$bgcolor,$textcolor等の変数を用意しておき

*****************************************************************

open (IN,"template.html");
print "Content-type: text/html\n\n";
while(<IN>){
  s/<!--title-->/$title/;
  s/<!--charset-->/$charset/;
   ・
   ・
   ・
 s/<!--message-->/$message/;
   ・
   ・
   ・
 s/<!--nextpage-->/$nextpage/;
 print ;
}

*******************************************************************
と置き換えていけばお望み通りのことができます。
ただし$messageの部分は1行ではすまないのでこの部分はスクリプトであらかじめ作ってやる必要があります。
例えばログファイルLOG.txtが
投稿者名:投稿日:内容
という書式で記録してあるとすれば

******************************************************************

open (INC,"LOG.txt");
$message="";
while(<INC>){
 ($name,$day,$mes)=split(':',$_);
  $message = "$message" .
"<table>\n
<tr><td>$name</td><td>$day</td></tr>\n
<tr><td colspan="2">$mes</td><tr>\n
</table><br>\n";
}

*****************************************************************
などとやります。leaz024さんが紹介されているモジュールも上に書いたようなルーチンをパッケージ化したものだと思われます。
なお上のスクリプトはささっと書いたのでコマンドのつづり間違い等があるかも知れませんがご容赦下さい。

Antsさんこんばんは。掲示板ソフトではそういう目的のために定番になっている手法があります。
モジュールがなくても大丈夫です。おそらくモジュールも同じようなことをやっているはずです。
例えば次のようなファイルをtemplate.htmlという名前で保存します
****************************************************

<html>
<head>
<title><!--title--></title>
<meta http-equiv="Content-Type" content="text/html; charset=<!--charset-->">
<meta http-equiv="Pragma" content="no-cache">
</head>
...続きを読む


このカテゴリの人気Q&Aランキング

おすすめ情報