我是XPATH和PHP的新手。我正试图在PHP中借助XPATH实现用户验证。我的数据在xml文件中
<?xml version="1.0" encoding="UTF-8"?>
<customers>
<customer>
<id>1</id>
<fName>sa</fName>
<lastName>aa</lastName>
<email>a@a.com</email>
<password>a</password>
</customer>
<customer>
<id>2</id>
<fName>bb</fName>
<lastName>cc</lastName>
<email>b@b.com</email>
<password>b</password>
</customer>
</customers>
我的php代码片段是
if(file_exists('customer.xml'))
{
$doc = new DOMDocument();
$doc->load('customer.xml');
$xpathvar = new Domxpath($doc);
//check if user exists and password matches
$queryResult = $xpathvar->query("customers/customer[email= '".$userEmail."' and password= '".$password."']");
var_dump($queryResult);
if(count($queryResult)== 1)
{
//successful login
echo "great";
}
else
{
echo "Invalid email address or password";
}
}
无论我提供什么输入,count($queryResult)
都返回1。不确定为什么没有进行正确的匹配。
当我提供$userEmail="a@a.com"
和$password="a"
时,var_dump($queryResult);
给出以下输出
object(DOMNodeList)[3]
public 'length' => int 0
if ($queryResult->length == 1)
并更改您的Xpath,因为它看不到根元素:
customer[email= '".$userEmail."' and password= '".$password."']
参见演示
将代码段更改为此
if(file_exists('customer.xml'))
{
$doc = new DOMDocument();
$doc->load('customer.xml');
$xpathvar = new Domxpath($doc);
//check if user exists and password matches
$queryResult = $xpathvar->query("/customers/customer[email= '".$userEmail."' and password= '".$password."']");
if($queryResult->length == 1)
{
//successful login
echo "great";
}
else
{
echo "Invalid email address or password";
}
}
何处
$queryResult->length is the number of all nodes that satisfy to the query
也在查询的开头加上/-斜杠
$queryResult = $xpathvar->query("/customers/customer[email= '".$userEmail."' and password= '".$password."']");
您不应该将密码本身存储在XML中,而应该将其存储在哈希中。因此,要从XML文件中获取密码,需要使用表达式,但要使用PHP函数进行验证。
您可以使用password_hash()
方法生成哈希:
var_dump(password_hash('a', PASSWORD_DEFAULT));
输出:
string(60) "$2y$10$o.aLdT4.xF6DaSaZAE4/8./omHnN5p3hBpfgzxSRwnXwdcfR27ova"
DOMXpath::evaluate()
支持返回标量值的Xpath表达式。因此,可以直接将节点列表强制转换为字符串。如果节点列表为空,它将返回一个空字符串。
$userEmail = 'a@a.com';
$password = 'a';
$document = new DOMDocument();
$document->loadXml($xml);
$xpath = new DOMXpath($document);
$userPasswordHash = $xpath->evaluate(
sprintf(
'string(/customers/customer[email = %s]/password)',
quoteXpathLiteral($userEmail)
)
);
$isValid = (
$userPasswordHash != '' &&
password_verify($password, $userPasswordHash)
);
var_dump($isValid);
您可能会注意到,我使用了一个函数来引用$userEmail值。这样可以避免Xpath注入。想象一下,有人提供了一个$userEmail值,如"" or true()
。Xpath 1.0没有转义,只是不允许在双引号字符串中使用单引号,也不允许在单引号字符串中出现双引号。这是函数。
public function quoteXpathLiteral($string) {
$string = str_replace("'x00", '', $string);
$hasSingleQuote = FALSE !== strpos($string, "'");
if ($hasSingleQuote) {
$hasDoubleQuote = FALSE !== strpos($string, '"');
if ($hasDoubleQuote) {
$result = '';
preg_match_all('("[^'']*|[^"]+)', $string, $matches);
foreach ($matches[0] as $part) {
$quoteChar = (substr($part, 0, 1) == '"') ? "'" : '"';
$result .= ", ".$quoteChar.$part.$quoteChar;
}
return 'concat('.substr($result, 2).')';
} else {
return '"'.$string.'"';
}
} else {
return "'".$string."'";
}
}