連想配列の構造についての理解が間違っているに違いないことは十分に認めます。
次のログイン スクリプトは、SQL Server データベース (具体的には Azure SQL) からクエリされた $username のハッシュされたパスワードとソルトで構成される連想配列を $userdata に入力します。ただし、提供されたパスワードのハッシュを作成し、DB で見つかったハッシュされたパスワードと比較するコードの部分は、$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 への 2 倍の呼び出しが必要であり、連想配列がどのように構築されるか、および連想配列に格納されている情報をどのように使用できるかについては何も知りません。
取得しようとしているメソッドに対して間違った構造のオブジェクトをフェッチしているか、構文が単に悪いのではないかと思います。sql_* コマンドではなく、PDO を引き続き使用するつもりです。
編集:これをもっと簡単にしましょう:
$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 配列の形式が正しくないのでしょうか?