在函数中编写MySQLi预处理语句的正确方法?

Rea*_*ues 5 php mysql mysqli coding-style prepared-statement

准备好的陈述

好的,我刚开始看看MySQLi准备好的语句.这对我来说是一个很大的进步,因为我对MySQL和PHP都是非常新的,所以我对这个概念(可能大约一个小时的价值)有一个非常脆弱的把握,所以你的答案必须用同样的措辞,抱歉这个.

我想知道的是,如果我正确地写了一份准备好的陈述.没有什么比学习一个不正确并习惯它的方法更糟糕的了,因此编写整个项目效率低下.

要点:我有一个注册用户的函数,然后返回插入的id,因此是用户的引用id.

以前,我只是查询数据库,尽管使用了mysql_real_escape_string()类似的安全措施,但我被告知存在安全风险.

现在,它看起来像这样:(假设为了这个问题,定义了所有引用的变量,绑定的参数是字符串,并且所有被调用的函数都存在且正在工作).

function registerUser($username, $fname, $email, $password, $region, $activation) {
    $uniqueSalt = uniqueSalt();
    $password = sha1($uniqueSalt . $password);

    $mysqli = mysqli_connect('localhost', 'root', '', 'database');

    if ($stmt = $mysqli->prepare("INSERT INTO `users` VALUES('', ?, ?, ?, ?, '$password', '$uniqueSalt', '$activation')") ) {
        $stmt->bind_param("ssss", $username, $fname, $email, $region);
        $stmt->execute();
        $stmt->close();
    } else {
        echo 'error preparing statement';
    }

    return mysqli_insert_id($mysqli);
}
Run Code Online (Sandbox Code Playgroud)

问题

它似乎有效,但是:

1)这是执行预准备语句的正确语法吗?

2)我已将此函数所在的文件(称为function.php)包含在另一个名为init.php的文件中,该文件先前已定义该变量$mysqli.我发现如果我没有包含

$mysqli = mysqli_connect('localhost', 'root', '', 'database');
Run Code Online (Sandbox Code Playgroud)

我会收到一个错误.为什么我必须在函数内重新定义它?

3)当我之前在使用准备return mysql_insert_id()好的语句之前结束了这个功能时,我已经发现我必须使用mysqli_insert_id($mysqli).

如果我不在$mysqli括号内包含,我会收到错误mysqli_insert_id() expects exactly 1 parameter, 0 given.为什么会这样,为什么它与我之前的不同?

干杯,卢克.

Jar*_*ish 2

  1. 你的使用没有多大意义。来自PHP 手册示例

    $stmt = $mysqli->prepare("INSERT INTO CountryLanguage VALUES (?, ?, ?, ?)");
    $stmt->bind_param('sssd', $code, $language, $official, $percent);
    
    Run Code Online (Sandbox Code Playgroud)

    将其与您的使用情况进行比较:

    $stmt = $mysqli->prepare("INSERT INTO `users` VALUES('', ?, ?, ?, ?, '$password', '$uniqueSalt', '$activation')");
    $stmt->bind_param("ssss", $username, $fname, $email, $region);
    
    Run Code Online (Sandbox Code Playgroud)

    注意到什么奇怪的事情了吗?手动示例用作?占位符,然后您可以用它->bind_param()来创建替换集。所以我认为你的例子应该是:

    $stmt = $mysqli->prepare("INSERT INTO `users` VALUES('', ?, ?, ?, ?, ?, ?, ?)");
    $stmt->bind_param("sssssss", $username, $fname, $email, $region, $password, $uniqueSalt, $activation);
    
    Run Code Online (Sandbox Code Playgroud)

    不知道是$activation数字还是字符串值。(另外,我建议使用列名称,而不是在INSERT查询中省略它们。)

    现在,您所做的操作在许多情况下都应该有效,因为您正在创建单个 use 语句并使用变量扩展将其插入$pass, $uniqueSalt, $activation到正在准备的查询字符串中。如果您不小心'在查询中放入一个或多个变量,则不会出现这种情况,这些变量应该参数化(使用->bind_param()),或使用mysqli_real_escape_string()。然而,混合这些方法是一种糟糕的做法,并且违背了使用准备好的语句的目的。没有理由做前几项,但不做最后几项。

  2. 如果您的$mysqli变量是全局定义的,那么当您在函数中调用它时,您的变量“超出范围”,因此当不可用时,您无法使用它,除非您导入它或在本地​​(在函数中)创建另一个变量。您可以使用global $mysqli;函数内的语法导入它(只要它是全局创建的,而不是在另一个函数中本地创建的)。

  3. 这与#2 是同一个问题。请参阅: http: //php.net/manual/en/mysqli.insert-id.php

我的建议是使用PDO而不是mysql_/mysqli_函数。