5

我正在切换到 PDO 准备好的语句,但我的代码在获取和使用会话 ID 时遇到了问题。

当客户注册时 session_id 设置为等于 user_id(自动递增),并且 session_id 在用户返回时以相同的方式设置。这在切换到 PDO 之前工作正常,但现在在任何后续页面上都无法识别 session_id(它正在查看 'user_id' 为空)

我是否需要切换到使用 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()失败,因为此时,$stmt仍然引用INSERT您无法从中获取行的 SQL。

因此,您需要做的是执行一条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']$hashedpassword就像您在原始mysql_*()代码中所做的那样。

于 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 回答