注釈つけて書き直します。


PHP+textdbで、友人間のイベントへの参加履歴などを管理しています。
textdbへのレコード登録は上手く作れたのですが、レコードの編集や削除(パスワード認証)が作れません。

textdb書式
$no<>$name<>$hostname<>$password<>$date<>$memo<>$flag

例:(一行目は多重判断や$noの生成に使っています)
2<>B<>hogefuga<>08/06/30 00:00:00
2<>B<>hogefuga<>password<>08/06/30 00:00:00<>Bのメモ<>0<>
1<>A<>hogehoge<>password<>08/06/28 00:00:00<>Aのメモ<>0<>

$memoや$flagを編集し、レコードの順番や$noを変更せずに保存するにはどのようにしたら良いのでしょうか。

回答の条件
  • 1人10回まで
  • 登録:2008/07/10 10:48:55
  • 終了:2008/07/15 08:06:55

ベストアンサー

id:tukihatu No.1

牛乳先生(tukihatu)回答回数180ベストアンサー獲得回数322008/07/10 11:36:48

ポイント100pt

まず、やりたいことと、PHPの命令仕様を整理してみましょう。

書いていないのでわからないですが、おそらくtextdbをfopenのrで開いて読み出し、その後fopenのwで開いて新しいデータ+今までの中身を書き込んでいる、またはa+で開いてポインタ先頭に戻してetc...ということをやっているんだと予想します。

とすると上の状態の場合で、2のレコードを編集するとなると、

textdbを開き読み込み変数に代入し→全文検索して2のレコードがある行を探し→その部分の内容を書き換え→textdbを書き込みモードで開き→新たに上書きする

という処理を行えばいいわけです。

これをソースで簡単に書くとこうなります。

$textdbfile = "txt.dat";
$input["no"] = "2";//例えばフォームで入力したレコード番号が2なら
$textdb_dat = file($textdbfile);//ファイルを配列で読み込む

foreach($textdb_dat as $key => $var){
    $i = sprit("<>",$var);//さらに細かく切る
    if($i[0] == $input["no"]){//入力したNOとレコードの先頭のデータが同じなら
        $textdb_dat[$key] = $input['no'] . "<>" . $input['name'] . "\n";//入れたい項目が続く
    }else{
        $textdb_dat[$key] += "\n"; 
    }
}

//書き換え終わったら
$write_dat = join("",$textdb_dat);
$fp = fopen($textdbfile, "w");
fwrite($fp,$write_dat);
fclose($fp);

とこんな感じになります。テストしていないですけど、流れはこれです。

とすると削除も同じように、

if($i[0] == $input["no"]){//入力したNOとレコードの先頭のデータが同じなら
        $textdb_dat[$key] = $input['no'] . "<>" . $input['name'] . "\n";//入れたい項目が続く
}

この部分を

if($i[0] == $input["no"] && $i[3] == $input["pass"]){//入力したNOとレコードの先頭のデータが同じで、さらにパスワードが同じなら
        $textdb_dat[$key] = "";
}

こうすれば良いですよね^^

ただ、textdbの全文検索や全文書き込みはあんまりお勧めしません。

・textdbが死んだら簡単には復旧できない

・textdbが1mb超えたりしたら多分重いし書き込み大変

なので、textdbは一つにせず、レコード番号のついたテキストで分割するのを進めます。

例えば1.dat、2.dat...

バーミッション問題が少し難しいかもしれませんが、なれるとこちらのほうが楽ですね。

id:blaze

素晴らしい回答ありがとうございます。

何分PHPをいじり始めたのがつい最近で、関数のノウハウがまだ溜まっておりませんでした。

全文読み込み、対象要素の比較、一致、不一致時の処理…等、一先ず作っては見たのですが

編集したレコード以外が全て消えたりしておりました。

>書いていないのでわからないですが、おそらくtextdbをfopenのrで開いて読み出し、その後fopenのwで開いて新しいデータ+今までの中身を書き込んでいる、またはa+で開いてポインタ先頭に戻してetc...ということをやっているんだと予想します。

ご明察の通りです。学習参考にしたメールフォームのソース等が上記のような処理をしていて、

ファイルポインタの位置やらなんやらに苦労していました。

ファイルの扱いは

・open

・lock

・処理

・close

だと思っていた(理想だとも思っていた)ので、

$write_dat = join("",$textdb_dat);

$fp = fopen($textdbfile, "w");

fwrite($fp,$write_dat);

fclose($fp);

この処理が考えられませんでした。

レコードナンバーの管理ファイル、各種レコード番号のレコードファイル、と分散したほうが

確かに処理も軽くリスクも少ないですね。

とても勉強になりました。

上記を参考に、書いてみたいと思います。ありがとうございました。

2008/07/10 19:02:39
  • id:blaze
    出欠管理用の投稿フォームです。PHPで出力しています。

    <form action="$_SERVER['SCRIPT_NAME']" method="POST">
    <input type=hidden name=mode value="attn">
    <div class="node">
    <div class="name" style="background:$bg_color; color:$font_color;">$name</div>
    <div class="button">
    <input type=hidden name=name value="$name">
    <input name="act" type="submit" value="○">
    </div>
    <div class="button">
    <input type=hidden name=name value="$name">
    <input name="act" type="submit" value="×">
    </div>
    </div>
    </form>
    実際にはtextDBを参照し、登録人数分だけ繰り返し処理をしています。
  • id:blaze
    レコード登録処理です。

    function add() {
    global $ini;
    // Header Include
    include_once($ini['header']);
    include_once($ini['menu']);
    echo "\n";

    // ポストデータ処理
    foreach ($_POST as $key => $val) {
    $_POST[$key] = Cleaning($key,$val);
    }

    // 入力確認
    if ($_POST['name'] == "") { err($ini['err_name']); }
    if ($_POST['password'] == "") { err($ini['err_password']); }
    if ($_POST['memo'] == "") { err($ini['err_memo']); }


    // ログ読込&先頭行分解
    $fp= @fopen($ini['log'], "rb+") or err("ログファイルの読み込みに失敗しました");
    flock($fp, LOCK_EX);
    while ($data[] = fgets($fp, FILE_SIZE));
    list($lastno,$lastname) = explode("<>", array_shift($data));

    // ホスト名取得
    $hostname = gethostbyaddr( getenv('REMOTE_ADDR') );

    // 記事No取得
    $no = $lastno + 1;

    // 日付取得
    $reg_date = date($ini['date']);

    // 新規行追加
    array_unshift($data, "$no<>$_POST['name']<>$host_name<>$_POST['password']<>$reg_date<>$_POST['memo']<>0<>\n");
    array_unshift($data, "$no<>$_POST['password']<>$reg_date\n");

    // ログ更新
    rewind($fp);
    foreach ($data as $line) fputs($fp, $line);
    ftruncate($fp, ftell($fp));
    fclose($fp);

    // リロード
    header("Location: http://$_SERVER[HTTP_HOST]$_SERVER[PHP_SELF]");

    die;
    } /* close function regist */
  • id:blaze
    出欠管理フォームと、レコード登録フォームは別のファイルからです。

    textdb読み込み>$nameの数だけ繰り返し列挙>フォームにhiddenアーギュメントとして名前を送信>
    textdb読み込み、投稿された名前データと一致した場合に該当レコードの$flagを更新>
    レコード順を変えずに保存

    という編集と、

    textdb読み込み>投稿された$nameと$passwordを評価>$nameが存在し、$passwordが一致したら処理開始>
    既存の登録レコードを表示>投稿された各種データを該当レコードへ上書き、レコード順を変えずに保存

    という編集、及び
    textdb読み込み>投稿された$nameと$passwordを評価>$nameが存在し、$passwordが一致したら該当レコード削除


    という処理を予定しています。

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

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

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

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