phpについて質問です。

csvファイルを読み込み→上書きするスクリプトを作ってみましたがうまく行かないときがあり原因を考えています。
100行程度のcsvから任意の行($idで指定したもの)を書き換えたいのですが、どこかに間違いや改善点があればお願いします。
うまく動作しない理由が知りたいです。

<?php
//データの取り出し
$id = $_GET['id'];
$data = file("../data/file.csv");

//idで指定した行に書き込み
$data[$id] ="テスト書き込み";

//csvファイルにデータの書き込み
$file = fopen("data/file.csv","w+");
flock($file, LOCK_EX);
for($i=0; $i<count($data); $i++) {
fwrite($file,$data[$i]);
}
fclose($file);
?>

回答の条件
  • 1人10回まで
  • 登録:2006/11/04 01:10:41
  • 終了:2006/11/11 01:15:02

回答(7件)

id:m-nisi No.1

m-nisi回答回数159ベストアンサー獲得回数32006/11/04 01:35:30

ポイント17pt

$data = file("../data/file.csv");

$file = fopen("data/file.csv","w+");

ファイルの場所が違うみたいですけど、

これはいいのでしょうか?

http://q.hatena.ne.jp/answer

id:hanabusatsukasa

すみませんこれは単純ミスです。

「テスト書き込み」が書き込まれるときとそうでないときがあるんですよね。。。

2006/11/04 07:44:24
id:b-wind No.2

b-wind回答回数3344ベストアンサー獲得回数4402006/11/04 01:21:08

ポイント18pt

ざっと見る限り、

・上書き処理なのに、file 関数と fopen 関数に指定しているファイル名が違う

・マニュアルには file 関数は LOCK を取得するという表記は無い。同時リクエストがあった時にファイルは壊れる可能性が高い。

ところが疑問に思いました。

http://q.hatena.ne.jp/1162570238

id:hanabusatsukasa

すみません、ファイルのアドレスは単純ミスです。

「テスト書き込み」が書き込まれるときとそうでないときがあるんですよね。。。このスクリプトはhttp://php.s3.to/tt/tt4.phpここを見て作りました。lockは間違っているでしょうか、、、

2006/11/04 07:46:11
id:iketerummo No.3

iketerummo回答回数68ベストアンサー獲得回数42006/11/04 09:53:02

ポイント17pt

closeの前にunlockが抜けている

flock($file, LOCK_UN);

Lock間の処理時間を短くすればそれなりの要求にも対応させられます。

同時書き込み数件程度であれば問題ないと当方でテスト済み。それ以上であればDBのトランザクションをお使いください。

http://jp2.php.net/manual/ja/function.flock.php

id:hanabusatsukasa

ありがとうございます。

アンロックつけてみます。

根本的に違ってないようなのでうまく動作するときとしないときの差は、、もしかしたら契約しているサーバがあまりにも安価なところだったためかもしれないですね。

2006/11/04 20:43:48
id:iketerummo No.4

iketerummo回答回数68ベストアンサー獲得回数42006/11/04 11:04:50

ポイント17pt

http://testwiki.仮.jp/?PHP%2F%A5%D5%A5%A1%A5%A4%A5%EB%A5%ED%A5%C3%A5%AF%2F%A5%CE%A1%BC%A5%C8#f4a10010

補足:

もっと厳密に更に精度を上げたいのであればバッファを考慮することと、戻り値(flock,fclose)を取得し例外を追加してください。

そこまで精度を上げるなら、尚更DBのほうが良いという結論になってしましますが。。。

id:hanabusatsukasa

バッファ、知りませんでした勉強になります。

2006/11/04 20:44:13
id:tobeoscontinue No.5

tobeoscontinue回答回数214ベストアンサー獲得回数542006/11/04 16:29:02

ポイント17pt
$id = $_GET['id'];

$idを添字として使っているので数字かどうかチェック(http://q.hatena.ne.jp/1114406105]is_numericしてis_int)した方がいいでしょう。また代入する前に添字の範囲チェックもした方がいいでしょう。


$data[$id] ="テスト書き込み";

問題はこの代入でしょう。行の識別をfile()によって行っているので改行文字が必要です。これでは次の行と結合してしまい、上書きではなく、行の削除と挿入になってしまいます。

$data[$id] ="テスト書き込み\n"; // osによっては\r\nかも

書き込みはforもいいですがforeachの方が綺麗です。

またimplode()で長い文字列にして書き出すのも手です。

また上書きではなく、別の名前で書き出してオリジナルをリネームし、

書き出したファイルをリネームするとした方が安全です。

まぁ数百行のファイルで書き込めないという状況にはならないと思いますが。


ロックについては書き込みの時点では不十分でしょう。するならロックしてからReadしてWriteするようにしないと厳密にはまずいでしょう。

file()はパスしか受けつけないのでfgets()でfile()のような機能を作らないといけなくなるので面倒ですが。

id:hanabusatsukasa

やはり、

$data[$id] ="テスト書き込み\n";

こちらが動作するときと

指定した$id行が空欄になってしまうときがあります。

スクリプトを改善したので契約サーバに問題があるのでしょうか??

2006/11/04 20:47:03
id:tobeoscontinue No.6

tobeoscontinue回答回数214ベストアンサー獲得回数542006/11/04 22:02:19

ポイント17pt

>契約サーバに問題があるのでしょうか??

それは無いと思います。


$idと代入した後の$dataの値を確認してみてはどうでしょう

//idで指定した行に書き込み
$data[$id] ="テスト書き込み"."\n";
echo "id=".$id."<br>";
print_r($data);

例えば$id="a"でも動作しますが出力のfwrite($file,$data[$i]);ではアクセスされないので書き込まれません。またdata/file.csvが10行しかないのに$id=11としても書き込まれません。


>こちらが動作するときと指定した$id行が空欄になってしまうときがあります。

data/file.csvの確認の方法はどうしているのでしょう。

更新時間は合っていますか。

ブラウザーでしているのであれば、キャッシュの影響はないのでしょうか。

id:hanabusatsukasa

>ブラウザーでしているのであれば、キャッシュの影響はないのでしょうか。

 

たとえば20行目に{テスト書き込みを}書き込む様に命令したとしても、

19行目

21行目

のように{テスト書き込み}が書き込まれるべきところが抜け落ちてCSVファイルが書き込まれてしまいます。(毎回ではなくたまにですが)

原因はなにか見当がつきません、、、

 

本来ならば、

19行目

20行目 テスト書き込み

21行目

スクリプトが正常に動けば上記のように書き込まれるはずなのですが、、、

解決策は無いでしょうか、、、、

2006/11/04 22:28:57
id:tobeoscontinue No.7

tobeoscontinue回答回数214ベストアンサー獲得回数542006/11/05 00:16:56

ポイント17pt

>たとえば20行目に{テスト書き込みを}書き込む様に命令したとしても、

>19行目

>21行目

>のように{テスト書き込み}が書き込まれるべきところが抜け落ちてCSVファイルが書き込まれてしまいます。

確認ですが最初CSVファイルが

19行目 A
20行目 B
21行目 C

あった時、

19行目 A
20行目 C

と言うように最初20行目にあったものが抜けたようにたまになるということでしょうか。

CSVファイルは行の連続で19行目の次は21行目とはならないのですが

いずれにしろ抜けるためには

unset($data[$id]);

$data[$id] = NULL;

$data[$id] = "";

としなければならずうなづけないのですが。

最後の行が抜けるというのであれば$idによっては考えられますが。

違うphp scriptが同じCSVファイルに対して書き込んでいるということはありませんよねぇ。


そのためにも

//idで指定した行に書き込み
$data[$id] ="テスト書き込み"."\n";
echo "id=".$id."<br>";
print_r($data);

をしたら確認できると思うのですが。また再現性を確保するために違うファイルに書き出してみてどうでしょう。


またこのファイル(phpの方)はhanabusatsukasaさん以外の人も随時アクセスできる状態なのでしょうか。そうであれば同時に読み込みがあった場合、どちらかのアクセスが反映されないということは考えられますが抜ける原因にはならないですけど。

コメントはまだありません

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

絞り込み :
はてなココの「ともだち」を表示します。
回答リクエストを送信したユーザーはいません