在php中使用xpath的结果数量错误


using xpath in php wrong number of result

我是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
$queryResult是DOMNodeList对象,其属性长度是找到的节点数量。测试结果使用:
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."'";
  }
}