1

我完全承认一定对关联数组的构造有错误的理解。

以下登录脚本将使用关联数组填充 $userdata,该数组由 $username 的散列密码和从 SQL Server 数据库(具体为 Azure SQL)查询的盐组成。但是,用于创建所提供密码的哈希并与在数据库中找到的哈希密码进行比较的代码部分失败,错误表明 $userdata[password] 和 $userdata[salt] 未定义。

    <?php

    $username = $_POST['username'];  
    $password = $_POST['password'];

    // Connect to SQL Server
    include '../../phpconfig/connectstrings.php';

    try  
    {  
$conn = new PDO ( "sqlsrv:server = $serverstringname; Database = $databasestringname", "$usernamestringname", "$passwordstringname");  
$conn->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION, );  
    }

    catch ( PDOException $e )  
    {  
    print( "Error connecting to SQL Server." );  
    die(print_r($e));  
    }

    catch(Exception $e)  
    {  
    die(var_dump($e));  
    }


    //Query database for the hashed password and salt for the supplied username
    if(!empty($_POST)) {

        try
    {  
    $sql_select = $conn->prepare("SELECT password, salt FROM logins WHERE username = '$username'");  
    $sql_select->execute();  
    }
    catch(Exception $e)
    {
    die(var_dump($e));  
    }


    //Fetch all of the remaining rows in the result set  
    $userdata = $sql_select->fetchAll(PDO::FETCH_ASSOC);

    //check for a valid username  
    if(empty($userdata))  
    {  
    echo "User: $username was not found";  
    die;  
    }  

    //hash the queried salt and hash the supplied password  
    $hash = hash('sha256', $userdata['salt'] . hash('sha256', $password) );  

    //compare the hashed salted password supplied with that queried from database  
    if($hash = $userdata['password'])  
    {  
    echo "Welcome, $username!";  
    }  
    else  
    {  
    echo "Invalid password";  
    }  
                    }

    ?>

虽然我不怀疑从 $sql_select 获取数组之外的一些代码需要一些调试,但我无法做到这一点,因为 $userdata 似乎将所有关联数组数据分配给变量的单个部分,如所示以下转储的输出:

    var_dump($sql_select);  
    //output = object(PDOStatement)#2 (1) { ["queryString"]=> string(61) "SELECT password, salt FROM logins WHERE username = 'mrtactics'" } 

    list($a[0], $b[1]) = $userdata;  
    var_dump($a);  
    var_dump($b);  
    //output = array(1) { [0]=> array(2) { ["password"]=> string(64) "f24704c0ce72a618cf1738894ebdd6001f4d3329802ab83bd418df66cbc46b1a" ["salt"]=> string(3) "6e0" } } array(1) { [1]=> NULL }

    var_dump($userdata["salt"]);  
    //output = NULL

    var_dump($userdata['salt']);  
    //output = NULL

    var_dump($userdata['password']);  
    //output = NULL

    foreach ($userdata as $item => $value)  
    echo "$item: $value<br>";
    //output = 0: Array

    $password = $sql_select->fetchColumn(0);  
    $salt = $sql_select->fetchColumn(1);  
    var_dump($password);  
    var_dump($salt);  
    //output = string(64) "f24704c0ce72a618cf1738894ebdd6001f4d3329802ab83bd418df66cbc46b1a" bool(false)

显而易见的解决方法是查询提供的用户名的单个值并传递每个继承人各自的变量。但是,这需要对数据库进行两次必要的调用,而且我对如何构造关联数组以及如何使用存储在其中的信息一无所知。

我怀疑我要么为我试图从中检索的方法获取错误构造的对象,要么我的语法很糟糕。我确实打算继续使用 PDO 而不是 sql_* 命令。

编辑:让我们让它更简单,然后:

    $userdatasql = $sql_select->fetchAll(PDO::FETCH_ASSOC);
    $userdata['password']="f24704c0ce72a618cf1738894ebdd6001f4d3329802ab83bd418df66cbc46b1a";
    $userdata['salt']="6e0";
    var_dump($userdata);
    var_dump($userdatasql);
    var_dump($userdata['password']);
    var_dump($userdatasql['password']);

    //Dump of $userdata = array(2) { ["password"]=> string(64) "f24704c0ce72a618cf1738894ebdd6001f4d3329802ab83bd418df66cbc46b1a" ["salt"]=> string(3) "6e0" }
    //Dump of $userdatasql = array(1) { [0]=> array(2) { ["password"]=> string(64) "f24704c0ce72a618cf1738894ebdd6001f4d3329802ab83bd418df66cbc46b1a" ["salt"]=> string(3) "6e0" } }

注意到这 2 个数组的构造不同了吗?我不知道这到底是什么意思,这就是我在这里的原因。如果我猜测 $userdatasql 数组似乎在数组中包含一个数组,因此必须对调用进行索引。

    //Dump of $userdata['password'] = string(64) "f24704c0ce72a618cf1738894ebdd6001f4d3329802ab83bd418df66cbc46b1a"
    //Dump of $userdatasql['password'] = NULL

更多信息:

    echo (count($userdata));
    echo (count($userdatasql));
    //output = 2
    //output = 1
    echo (count($userdata, 1));
    echo (count($userdatasql, 1));
    //output = 2
    //output = 3

这告诉我,由 PDO FETCH_ASSOC 创建的数组与手动创建的数组具有不同的结构,但包含相同的 2 条数据和相同的 2 个索引。

有了这些知识,我修改了我的转储以包含 0 索引位置,然后突然输出了预期的数据:

    var_dump($userdatasql['0']['password']);
    var_dump($userdatasql['0']['salt']);
    //password dump = string(64) "f24704c0ce72a618cf1738894ebdd6001f4d3329802ab83bd418df66cbc46b1a"
    //salt dump = string(3) "6e0"

这是否意味着我必须按索引引用所有 PDO FETCH ASSOC 数组?
我不应该这么想,因为我发现没有代码示例表明这一点。
那么,为什么我的 PDO FETCH ASSOC 阵列格式不正确?

4

1 回答 1

1

好吧,我有“答案”,因为我可以格式化语法以从关联数组中检索必要的信息。我不明白手动创建的关联数组和由 PDO FETCH ASSOC 创建的关联数组之间的区别,也不明白以后当我的数组比这里提出的数组复杂得多时会产生什么影响。

但是,这是“答案”:

存储在由 PDO FETCH ASSOC 创建的关联数组中的信息必须由数字索引引用 THEN 关联索引,尽管它不是数字类型的关联数组(因为这很有意义,对吧?)通过在前面包含数字索引对于关联索引,该值已正确获得。

    $var[0][index] //retrieves correctly
    $var[index]  //does not unless the array happened to be manually constructed

在研究其他相关代码示例数小时后得出的最终答案是:

我的代码按原样执行是因为我使用的是 ->fetchAll 而不是 ->fetch。当我简单地使用 ->fetch 时,我不再需要同时引用数字索引和关联索引,并且可以像关联数组的预期那样简单地引用关联索引。

更正后的代码语法如下:

    <?php


    $username = $_POST['username'];
    $password = $_POST['password'];

    // Connect to SQL Server
    include '../../phpconfig/connectstrings.php';

    try
    {
    $conn = new PDO ( "sqlsrv:server = $serverstringname; Database = $databasestringname", "$usernamestringname", "$passwordstringname");
    $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    }

    catch ( PDOException $e )
    {
    print( "Error connecting to SQL Server." );
    die(print_r($e));
    }

    catch(Exception $e)
    {
    die(var_dump($e));
    }


    //Query database for the hashed password and the salt for the supplied username
    if(!empty($_POST)) {

    try
    {
    $sql_select = "SELECT password, salt FROM logins WHERE username = ?";
    $stmt = $conn->prepare($sql_select);
    $stmt->bindValue(1, $username);
    $stmt->execute();
    }

    catch(Exception $e)
    {
    die(var_dump($e));
    }


    //Fetch the result set into an associative array
    $userdata = $stmt->fetch(PDO::FETCH_ASSOC);

    if(empty($userdata))
    {
    echo "User: $username was not found";
    die;
    }


    //hash the queried salt with a hash of the supplied password
    $hash = hash('sha256', $userdata['salt'].hash('sha256', $password));

    //compare the hashed salted password supplied with that queried from database
    if($hash == $userdata['password'])
    {
    echo "Welcome, $username!";
    }
    else
    {
    echo "Invalid password";
    //does the user wish to register> -> header('Location: register.php');
    die;        
    }
        }

    ?>
于 2012-12-03T20:27:24.387 回答