5

PDOプリペアドステートメントに切り替えていますが、セッションIDを取得して使用するためのコードに問題があります。

顧客が登録すると、session_idはuser_id(自動インクリメント)と等しくなるように設定され、session_idはユーザーが戻ったときに同じ方法で設定されます。これは、PDOに切り替える前は正常に機能していましたが、以降のページでsession_idが認識されなくなりました(「user_id」がnullとして表示されます)

PDOセッションハンドラーの使用に切り替える必要がありますか、または使い慣れた方法を引き続き使用する方法はありますか?

mysql-これは、セッションIDを設定するために使用していたコードです(これは正しく機能しました):

// Statements defining $user_name, $password and $hashedPassword (as shown below), and mysql_real_escape_string
// Insert statement
if($result) { 
$qry="SELECT * FROM customer_info WHERE user_name='$user_name' AND password='".sha1($salt + $_POST['password'])."'";
$result=mysql_query($qry);
if($result) {
    if(mysql_num_rows($result) == 1) {
    session_regenerate_id();
    $member = mysql_fetch_assoc($result);
    $_SESSION['SESS_USER_ID'] = $member['user_id'];
    session_write_close();
    exit();
    } } }

PDO-これは私が試したコードです(セッションIDは設定されていません):

$user_name = $_POST['user_name'];
$password = $_POST['password'];  
$hashedPassword = sha1($salt . $password); 
$stmt = $conn->prepare('INSERT INTO customer_info (...) VALUES(...)');
$stmt->bindParam(':user_id', $user_id); 
...  
$insertResult = $stmt->execute();  
if ($insertResult) {
    $qry="SELECT * FROM customer_info WHERE user_name = $user_name AND password=$hashedPassword";
    if($qry) {
        $affected_rows = $stmt->rowCount();
        if ($affected_rows == 1)  {   
            session_regenerate_id();
            $member = $stmt->fetch();
            $_SESSION['SESS_USER_ID'] = $member['user_id'];   
        }  

後続のページでセッションIDを参照できるようにする追加のコード

このコードは、後続のすべてのページの上部にあります。

<?php
  //Starts session and checks if the session variable SESS_USER_ID is present or not
  require_once('auth.php');  
  //Database connection and Open database
  require_once('config.php');  
  $user_id = $_SESSION['SESS_USER_ID']; 
?>

auth.phpファイル

<?php
session_start();
if(!isset($_SESSION['SESS_USER_ID']) || (trim($_SESSION['SESS_USER_ID']) == '')) {
    header("location: login_failed.html");
    exit();
}
?>
4

2 に答える 2

2

$stmt->fetch()この時点では、まだ行をフェッチできない $stmtSQLを参照しているため、への呼び出しは失敗します。INSERT

したがって、実行する必要があるのは、SELECTステートメントを実行して、新しく入力されたユーザーの詳細を取得しfetch()、代わりにそこから取得することです。customer_infoテーブルに自動インクリメント列があると仮定して、を使用PDO::lastInsertId()して新しい行のIDを取得し、SELECTクエリで使用します。

$user_name = $_POST['user_name'];
$password = $_POST['password'];  
$hashedPassword = sha1($salt . $password); 
$stmt = $conn->prepare('INSERT INTO customer_info (...) VALUES(...)');
$stmt->bindParam(':user_id', $user_id); 
...  
$insertResult = $stmt->execute();  
if ($insertResult && $stmt->rowCount() == 1) {
  // Ok, the INSERT was successful, so now SELECT the row back
  // Use lastInsertId() to get the new row's id
  // Assuming the id column is `user_id`...
  $stmt_user = $conn->prepare("SELECT * FROM customer_info WHERE user_id = :user_id");
  $stmt_user->bindValue(":user_id", $conn->lastInsertId());
  $stmt_user->execute();

  session_regenerate_id();
  // Fetch from the SELECT query
  $member = $stmt_user->fetch();
  $_SESSION['SESS_USER_ID'] = $member['user_id'];   
}

私が想定したような自動インクリメント列がない場合は、元のコードと同じように、入力をバインドuser_idしてクエリを実行できます。user_namepassword$_POST['user_name']$hashedpasswordmysql_*()

于 2012-12-31T19:25:55.323 に答える
2

質問に非常に具体的にする

PDO-これは私が試したコードです(セッションIDは設定されていません):

$user_name = $_POST['user_name'];
$password = $_POST['password'];  
$hashedPassword = sha1($salt . $password); 
$stmt = $conn->prepare('INSERT INTO customer_info (...) VALUES(...)');
$stmt->bindParam(':user_id', $user_id); 
...  
$insertResult = $stmt->execute();  
if ($insertResult) {
    $qry="SELECT * FROM customer_info WHERE user_name = $user_name AND password=$hashedPassword";
    if($qry) {
        $affected_rows = $stmt->rowCount();
        if ($affected_rows == 1)  {   
            session_regenerate_id();
            $member = $stmt->fetch();
            $_SESSION['SESS_USER_ID'] = $member['user_id'];   
        } 

ここで、コードを注意深く見て、セッションIDをいつ設定する必要があるかを自分で答えてください。
これは、次の場合に実行する必要があります。

1)そうで$insertResultはありませんFALSE

ああ、あなたのコードに明らかなエラーがあるので、ここでやめて説明させてください-

$qry="SELECT * FROM customer_info WHERE user_name = $user_name AND password=$hashedPassword";

この場合、これは単なるダムストリングです。したがって、命令自体は次のようになります。

if ($insertResult) { //Which always will be TRUE regarding result as the string isn't empty!!! 

if ($affected_rows == 1)  {   //if the number of affected rows == 1

次に、セッションIDを挿入します


何が間違っているのか

1)エラーを追跡しないため、エラーの性質を正確に把握できません
。2)SQLステートメントを実行せず、結果を取得しません
。3)行数が「失敗」の場合、これを追跡しません。ただし、代わりにこれを無視してください

代わりにすべきこと

1)ステートメントを実行します:( $qry="SELECT * FROM customer_info WHERE user_name = $user_name AND password=$hashedPassword";SQLステートメントにも変数が含まれています。これは古いmysql_*関数から取得したようです)

$stmt->prepare("SELECT * FROM customer_info WHERE user_name = :user_name AND password=:hashedPassword LIMIT 1;"); 
$stmt->execute(array(':user_name' => $username, ':hashedPassword' => $hashedPassword))); 
$result = $stmt->fetchAll(PDO::FETCH_ASSOC)

//now check $result if it found the row, like

if ( $result ){
   // found
} else {
   // not found, do track an error here
}

2)繰り返します-エラーを追跡します。カスタムエラーハンドラーを実装することをお勧めしますが、例として、配列を使用できます。
次のようになります。

<?php

//at the bottom of the script
$errors = array();

...
...

if ( $result ){
  // do next stuff
  ...
} else {
  //add an error
  array_push('Incorrect data', $errors);
}

次に、どこかで、そのエラーを単純に印刷できます。

//We won't use a global keyword
function print_errors(array $errors){

   if ( !empty($errors) ){
        foreach($errors as $error){
           print '<p><li>' . $error . '</li></p>';
        }

   }
}


//Use like this:
print_errors($errors);

これにより、正確にスタックした場所に自信が持てるようになります

于 2012-12-31T19:54:22.050 に答える