我完全承认必须对关联数组的构造有错误的理解。
以下登录脚本将填充$ userdata,其中包含一个关联数组,该数组包含$ username的哈希密码和从SQL Server数据库查询的salt(特定于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)
明显的解决方法是查询提供的用户名的单个值,并传递每个相应的变量。但是,这需要对DB进行两次必要的调用,而且我没有学习如何构造关联数组以及如何使用存储在其中的信息。
我怀疑我要么为我正在尝试从中检索的方法获取错误构造的对象,要么我的语法非常糟糕。我打算继续使用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" } }
注意这两个阵列结构的差异?我不知道究竟是什么意思,这就是我在这里的原因。如果我猜测$ 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阵列格式不正确?
答案 0 :(得分: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
最后,作为真正的答案,在数小时研究其他相关代码示例后推断:
我的代码按原样执行,因为我使用的是&gt; fetchAll而不是 - &gt; fetch。当我简单地使用 - &gt; 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;
}
}
?>