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

时间:2016-05-15 15:31:33

标签: php xml xpath

我是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

3 个答案:

答案 0 :(得分:1)

$ queryResult是DOMNodeList对象,其属性长度是找到的节点的数量。测试结果使用:

if ($queryResult->length == 1)

并更改您的Xpath,因为它没有看到根元素:

customer[email= '".$userEmail."' and password= '".$password."']

see demo

答案 1 :(得分:0)

将代码段更改为此

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

还将/ -Slash放在查询的开头

$queryResult = $xpathvar->query("/customers/customer[email= '".$userEmail."' and password= '".$password."']");

答案 2 :(得分:0)

您不应将密码本身存储在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."'";
  }
}