2012-03-15 12 views
0

私の新しいウェブサイトの機能をいくつか作成した後、永続的なプログラミングを使ってすべてのインクルードファイルを手に入れていることをすぐに知ったので、私は自分の現在の関数を学び、OOPクラスに変換し、 mysqli。これまでのところ変わっていませんでしたが、複数のクエリが必要な関数に到達しました.1つは、データを更新する前にSELECTをチェックするSELECTです。私が今までに書いたのは、準備されたステートメントを使って、魅力的に動作しますが、SELECTだけです。私が立ち往生している場所は、dbを更新する時間です。mysqli(マルチ)_query - どのようにしてループで実行するのですか?

public function ban() { 
    $connection = Database::getConnection(); 
    $user_id = $_POST['user']; 
    $feedback = ''; 
    $query = "SELECT banned, user_name 
      FROM users 
      WHERE user_id = ?"; 
    $stmt = $connection -> prepare($query); 

    // Check for a multi-user selection on POST 
    if (count($user_id) > 1) { 
    foreach ($user_id as $value) { 
     $stmt -> bind_param('i', $value); 
     if (!$result = $stmt -> execute()) { 
      $feedback .= "Did not execute."; 
     } else { 
      $stmt -> bind_result($banned, $user); 
      $stmt -> fetch(); 
      if ($banned == 1) { 
       $feedback .= $user . " is already banned.<br />"; 
      } else { 
       // This is where I need the code to update the database 
       // with the users who aren't already banned. 
      } 
     } 
    } 
    $stmt -> close(); 
    return $feedback; 
    } else { 
    // This is where the UPDATE will be for a single person ban 
    // if only one was selected on POST 
    } 
} 

私はセクション内の別のループ内で私は、コードを必要とするか、それはそれを避けるために最善だろうと実行し、UPDATE注入のための第二プリペアドステートメントを実行する/作成することができ、または:ここでは私がこれまで持っているものですそれは働くだろうか? mysqli_multi_queryはおそらく、関数を再度書き直す必要はないと思います。なぜなら、(関数の多くを書いた後で)multi_queryインジェクションでプリペアドステートメントを使用できないことがわかったからです。書き換えは大したことではありませんが、multi_queryの使用には手間がかかります。 PHPのウェブサイトには多くのドキュメントがありますが、正直なところ、混乱することはありません。

UPDATEクエリは次のようになります:これで

$explain = mysql_real_escape_string($_POST['banExplain']); 
UPDATE users 
SET banned = '1', ban_reason = '$explain' 
WHERE user_id = '$value'" 

任意の助けいただければ幸いです。私が必要とすることを十分に説明してくれることを願っています。そうでない場合は、私に知らせてください。ありがとう!

答えて

1

コードサンプルは非常に手続き的です。

ユーザーがuser_bannedであるかどうかを確認する方法と、ユーザーをban_userにする方法が必要です。

user_bannedメソッドはuser_idをとり、ブール値を返す必要があります。

ban_userメソッドにはreasonとuser_idが必要です。

ループを実行する別の関数またはメソッドが必要です。

user_idを配列としてキャストし、1つのループを実行できます。

例外を使用してエラーを処理します。

<?php 
    //the model 
    ... 

    public function update_users (array $user_ids) 
    { 
     $result = array();   

     foreach ($user_ids as $user_id) { 
      if (!$this->user_banned($user_id)) { 
       $this->ban_user($user_id, $reason); 

      } else { 
       $result[$user_id] = "already banned"; 
      } 

     return $result; 
    } 
    ... 

    //the controller 

    //prevent XSS, cast as integers or use filter_var or something 
    $user_ids = sanitize((array) $_POST['user']); 
    try { 
     $result = $obj->update_users($user_ids); 
    } catch (Exception $e) { 
    ... 
+0

あなたの権利では、コードはまだ非常に手続き的です。質問を投稿した後、私は解決策を考え出しましたが、もっと長めのバージョンではありませんでした(私の答えをご覧ください)。私は今あなたのアドバイスを受け取り、もっと小さく、より多くのOOPスタイルの関数に分解できるかどうかを見ていきます。 –

0

私の質問を読み返したので、私は更新のために2番目の準備文を使用することを考えました。最初に、最初のforeachループ内に2番目のステートメントを含めることを試みましたが、1度に1つ以上のステートメントを開くことができないため、おそらくエラーが発生しました。私が次に決定したのは、最初のforeachループとプリペアドステートメントを閉じた後、UPDATEとvoilaの新しい準備文を使用して2番目のループを実行したときに、各繰り返しに値(ユーザーIDがチェックされています)を保存することでした。それが今見えるようここでは、コードは次のようになります。

public function ban() { 
    $connection = Database::getConnection(); 
    $user_id = $_POST['user']; 
    $reason = $_POST['banExplain']; 
    $update = array(); 
    $feedback = ''; 
    $query = "SELECT banned, user_name 
      FROM users 
      WHERE user_id = ?"; 
    $query2 = "UPDATE users 
      SET banned = '1', ban_reason = ? 
      WHERE user_id = ?"; 
    $stmt = $connection -> prepare($query); 
    $stmt2 = $connection -> prepare($query2); 

    if (count($user_id) > 1) { 
    foreach ($user_id as $value) { 
     $stmt -> bind_param('i', $value);    
     if (!$result = $stmt -> execute()) { 
      $feedback .= "Did not execute search.<br />"; 
     } else { 
      $stmt -> bind_result($banned, $user); 
      $stmt -> fetch(); 
      if ($banned == 1) { 
       $feedback .= $user . " is already banned.<br />"; 
      } else { 
       $update["$user"] = $value; // Populate an array to pass to update loop 
      } 
     } 
    } 
    $stmt -> close(); 

    // Run update query - $key from $update var is the user name 
    foreach ($update as $key => $value) { 
     $stmt2 -> bind_param('si', $reason, $value); 
     if (!$result2 = $stmt2 -> execute()){ 
      $feedback .="Did not execute update.<br />"; 
     } else { 
      $feedback .= $key . " is banned.<br />"; 
     } 
    } 
    $stmt2 -> close(); 
    return $feedback; 
    } else { 

    // Executes for single selection requests 
    $stmt -> bind_param('i', $user_id); 
    if (!$result = $stmt -> execute()) { 
     $feedback .= "Did not execute search.<br />"; 
    } else { 
     $stmt -> bind_result($banned, $user); 
     $stmt -> fetch(); 
     if ($banned == 1) { 
      $feedback .= $user . " is already banned.<br />"; 
     } else { 
      $update["$user"] = $user_id; 
     } 
    } 
    $stmt -> close(); 
    // Runs loop simply for the user name in the $key var 
    foreach ($update as $key => $value) { 
     $stmt2 -> bind_param('si', $reason, $value); 
     if (!$result2 = $stmt2 -> execute()){ 
      $feedback .="Did not execute update.<br />"; 
     } else { 
      $feedback .= $key . " is banned.<br />"; 
     } 
    } 
    $stmt2 -> close(); 
    return $feedback; 
    } 

}

むしろ、このような簡単な作業のようです何のために長い、と私はmysqli::multi_query約行くための最善の方法は、おそらくまだあると思っていますこれは(必要なセキュリティを追加するためにmysqli::real_escapeを使用した後に)、しかしこの機能の嵩張り以外は、動作し、サーバーの要求コストを最小限に抑えながら(私が知る限り)安全です。

私は今、user934258のアドバイスを受け取り、これをより小さく、簡単にダイジェストし、クラス機能を維持するように解説します。もし私がそれを完了したら、私は同じ苦境で他の人を助けることになる結果を示すためにここにフォローアップします。他に誰かが良い解決策を持っているなら、私に知らせてください。私はいつも私のコーディングを改善しようとしています

ありがとう、これは少なくとも同じ状況で誰かを助けることを願っています。


いいえよく、thanks to user934258私は戻って、この/これらの方法のコーディングを再検討しました。彼のアドバイスを受けて、禁止方法から約25行のコードを削除することができました。しかし、余分な引数を渡して余分な引数を渡すだけで、私はコードをunbanメソッドを組み込む多目的にすることができ、不要な繰り返しコードの約77行が削除されました(unbanはそれ以外の禁止はDBのOneの代わりにZeroをチェックし、少し異なるレスポンスを表示しました。)このトピックが参考になるかもしれないあなたの将来については、ここに私のコードの最終製品があります。

スクリプトから呼び出されるメソッド:DB禁止値をチェックする

public function ban($arg) {    // 0 = Unban 1 = Ban 
    $this -> user_id = $_POST['user'];  // initially set user id as global variable 
    $user_id = $this -> user_id; 
    $this -> banReason = mysqli_real_escape_string($_POST['banExplain']); 

    if (!$this -> check_ban($user_id, $arg)) { 
    $this -> feedback .= Admin::CONNFAIL; 
    return $this -> feedback;   // Returned connection failure on select 
    } elseif (!$this -> ban_user($arg)) { 
    $this -> feedback .= Admin::UPFAIL; 
    return $this -> feedback;   // Returned connection failure on update 
    } else { 
    return $this -> feedback; 
    } 
} 

は方法(複数可):

private function check_ban($user_id, $arg) { 
    $connection = Database::getConnection(); 
    $query = "SELECT banned, user_name 
      FROM users 
      WHERE user_id = ?"; 
    $stmt = $connection -> prepare($query); 

    foreach ($user_id as $value) { 
    $stmt -> bind_param('i', $value); 
    if (!$result = $stmt -> execute()) { 
     return FALSE; 
    } else { 
     $stmt -> bind_result($banned, $user); 
     $stmt -> fetch(); 
     if ($arg == 1 && $banned == 1) { 
      $this -> feedback .= $user . " is already banned.<br />"; 
     } elseif ($arg == 0 && $banned == 0) { 
      $this -> feedback .= $user . " is not currently banned.<br />"; 
     } else { 
      $this -> update["$user"] = $value; // Populate array to be un/banned 
     } 
    } 
    } 
    $stmt -> close(); 
    return TRUE; 
} 

そして最後に、UN /禁止してDBを更新する方法:

private function ban_user($arg) { 
    $connection = Database::getConnection(); 
    $update = $this -> update; 
    $reason = $this -> banReason; 
    $query = "UPDATE users 
      SET banned = ?, ban_reason = ? 
      WHERE user_id = ?"; 
    $stmt = $connection -> prepare($query); 

    foreach ($update as $key => $value) { 
    $stmt -> bind_param('isi', $arg, $reason, $value); 
    if (!$result = $stmt -> execute()) { 
     return FALSE; 
    } elseif ($arg == 0) { 
     $this -> feedback .= $key . " is unbanned.<br />"; 
    } else { 
     $this -> feedback .= $key . " is banned.<br />"; 
    } 
    } 
    $stmt -> close(); 
    return TRUE; 
} 

これらのメソッドでは、エラーチェック/フィルタリング/サニタイズがほとんど発生していないことに注意してください。私はこれのためのいくつかの理由があります:変数の値はスクリプトでチェックされて、私は唯一のこれを行うための権利を与えられていると$user_idのような値のためのチェックボックスとドロップダウンリストに正確にdbからの値が間違っている可能性があります。$user_idはどれもスリムではありません。

私が他の記事で述べたように、誰かが私がしたことに対してより良い解決策を提供できる場合は、私に知らせてください。

このような素晴らしいコミュニティに感謝します。

関連する問題