いつもお世話になってます。
フォームからメールアドレスを入力して、ログファイルに書き込みする簡易プログラムを作りました。
重複させたくないので、array_unique関数を使って、重複した配列を削除させることにしましたが、最新で重複したもの2件だけは残ってしまいます。(意味分かりますかね?)2件だけ必ず重複が残ってしまうのです。そこから何回同じ内容を送信しても、2件以上重複になることはありません。
あと、あわよくば、『すでに登録済です』とメッセージも出せたら最高なのですが・・・。
【スクリプト】
<?php
$mail=$_POST['mail'];
$string = $mail."\n";
$lines = file("mail.log");
$fp = fopen("mail.log", "w"); // ファイルを書き込み用にオープン
fputs($fp, $string);
for($i = 0; $i < count($lines); $i++){
$lines2 = array_unique($lines);
fputs($fp, $lines2[$i]);
}
$fp = fclose($fp); // ファイルをクローズ
?>
こんばんは。
処理ですが、
ファイルを$linesに全部読み込む
ファイルに新しいアドレスを書き込む
$linesの行数を元に値を比較し書きこむ
問題点
1.$linesには新しく書きこんだアドレスが入って無い。
なので、重複したデータが必ず先頭行に残る。はず。
2.array_uniqをforでまわす根拠がない。一度でいいです。
使っている関数を同じ感じだと、こんなんです。
新しいアドレスをaで追加書き込み
一応閉じてからもう一度開いて、
uniqe
で書き込み
一行ずつ書きこむのにforでやっていますが、
wrapされているfile_put_contentsでやったほうが見た目が多少いいかと思います。
<?php $mail=$_POST['mail']; $string = $mail."\n"; $fp = fopen("mail.log", "a"); // ファイルを追加書き込み用にオープン fputs($fp, $string); $fp = fclose($fp); // ファイルをクローズ $lines = file("mail.log"); $fp = fopen("mail.log", "w"); // ファイルを書き込み用にオープン $lines2 = array_unique($lines); for($i = 0; $i < count($lines2); $i++){ fputs($fp, $lines2[$i]); } $fp = fclose($fp); // ファイルをクローズ ?>
こんばんは。
処理ですが、
ファイルを$linesに全部読み込む
ファイルに新しいアドレスを書き込む
$linesの行数を元に値を比較し書きこむ
問題点
1.$linesには新しく書きこんだアドレスが入って無い。
なので、重複したデータが必ず先頭行に残る。はず。
2.array_uniqをforでまわす根拠がない。一度でいいです。
使っている関数を同じ感じだと、こんなんです。
新しいアドレスをaで追加書き込み
一応閉じてからもう一度開いて、
uniqe
で書き込み
一行ずつ書きこむのにforでやっていますが、
wrapされているfile_put_contentsでやったほうが見た目が多少いいかと思います。
<?php $mail=$_POST['mail']; $string = $mail."\n"; $fp = fopen("mail.log", "a"); // ファイルを追加書き込み用にオープン fputs($fp, $string); $fp = fclose($fp); // ファイルをクローズ $lines = file("mail.log"); $fp = fopen("mail.log", "w"); // ファイルを書き込み用にオープン $lines2 = array_unique($lines); for($i = 0; $i < count($lines2); $i++){ fputs($fp, $lines2[$i]); } $fp = fclose($fp); // ファイルをクローズ ?>
うわ~~!そうだったのですね。
問題点を指摘され、『そうだったのか~!』と、叫んでしまいました。
まだPHP初心者のため、大変参考になりました。感動です。
もし、お手数でなければ、file_put_contentsをなぜ使ったほうがよいのかがいまいち分かりません。
教えていただけると幸いです。
入力されたメールアドレスを配列に入れていないのでarray_unique関数では消せません。
改行削除モードでfile関数で開きin_array関数を使えばarray_uniqueは使わなくても重複しません。
<?php$mail = trim(stripslashes($_POST['mail']));
$lines = file('mail.log', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
if( in_array($lines,$mail) ) {
echo "そのアドレスは既に登録済みです";
} else {
array_unshift($lines,$mail);
$lines = array_unique($lines);
$fp = @fopen('mail.log','w');
if( $fp ) {
if(flock($fp, LOCK_EX)){
foreach( $lines as $line ) {
fwrite($fp,$line."\n");
}
flock($fp,LOCK_UN);
} else {
echo "ファイルロック失敗";
}
$fp = fclose($fp);
} else {
echo "ファイル書き込みオープン失敗";
}
}
?>
>改行削除モードでfile関数で開きin_array関数を使えばarray_uniqueは使わなくても重複しません
なるほど、そうなのですね!参考になります。
エラー処理まで書いて頂いて、ありがとうございました!
重複してしまう原因は、フォームから入力されたメールアドレス( = $string)が
それまで蓄積したメールアドレス( = $lines)と重複しているかチェックしていない為です。
mail.logには重複を許さない条件で保存しているので、ここから配列($lines)を作り
この配列に対してarray_uniqueを使うのはややもったいない感じです。
(個人的にはarray_uniqueはゴチャ混ぜのところから、重複を取り除く時に使いやすいものと感じます。)
で、私だったらということですが
$mail=$_POST['mail'];
$string = $mail."\n";
$lines = file("mail.log");
if(in_array($string, $lines)){
echo "すでに登録済です";
}else{
$lines[] = $string;
$tmp = implode('', $lines);
$fp = fopen("mail.log", "w"); // ファイルを書き込み用にオープン
fputs($fp, $tmp);
$fp = fclose($fp); // ファイルをクローズ
}
?>
という所でしょうか?
あと、このままですとフォームからデータを送信するタイミングによって
データが壊れる可能性があります。
具体的にはfopen()~fclose()の間に、file()が生じると、
$linesが正しく全てのデータを読み込めていないことになります。
複数の人がほぼ同時にこのフォームを使う事を考慮する必要があれば工夫が必要という事です。
flock()あたりを参考にしてみて下さい。
>複数の人がほぼ同時にこのフォームを使う事を考慮する必要があれば工夫が必要という事です。
flock()あたりを参考にしてみて下さい。
↑↑↑↑
なるほど、そこは盲点でした。そのことを全く考えていませんでした。さっそくやってみようとおもいます。
「すでに登録済みです」とメッセージを出すのであれば、array_unique()はいらないですね。
<?php $mail=$_POST['mail']; $string = $mail."\n"; $lines = file("mail.log"); if( in_array($string, $lines, true) ){ print "すでに登録済です"; }else{ array_unshift($lines, $string); $fp = fopen("mail.log", "w"); for($i = 0; $i < count($lines); $i++){ fputs($fp, $lines[$i]); } $fp = fclose($fp); } ?>
>「すでに登録済みです」とメッセージを出すのであれば、array_unique()はいらないですね。
え~!いらないんですか!
でもとても参考になります。ありがとうございます。コードもわかりやすかったです
処理の流れをみると判る
(1)ファイルから読み込み
$lines = file("mail.log");
(2)ファイルへ追加
$fp = fopen("mail.log", "w"); // ファイルを書き込み用にオープン
fputs($fp, $string);
(3)重複削除
$lines2 = array_unique($lines);
(3)の時点で相手にしている$linesは (1)の時点でのファイルの内容だから(2)で追加した分は含まれていない
だから必ず同一のもの2つが存在可能となっている
本来の流れとしては
(1)ファイルから読み込み
(2)既存かどうかの確認
array-searchという関数で $lines に $string が含まれているかどうかを確認
http://jp.php.net/manual/en/function.array-search.php
(3a)含まれていなければファイルへ追加して「登録しました」をecho
(3b)既存であれば「すでに登録済です」をecho
となる
なるほど、最初に処理の流れを考えなければいけないのですよね、痛感しました。とても参考になりました、ありがとうございます!
うわ~~!そうだったのですね。
問題点を指摘され、『そうだったのか~!』と、叫んでしまいました。
まだPHP初心者のため、大変参考になりました。感動です。
もし、お手数でなければ、file_put_contentsをなぜ使ったほうがよいのかがいまいち分かりません。
教えていただけると幸いです。