如何在PHP中使用mysqli预处理语句?

时间:2012-03-09 05:23:21

标签: php mysql mysqli

我正在尝试预备语句,但下面的代码不起作用。我收到了错误:

  

致命错误:在非对象中调用成员函数execute()   第12行/var/www/prepared.php

<?php

    $mysqli = new mysqli("localhost", "root", "root", "test");
    if ($mysqli->connect_errno) {
        echo "Failed to connect to MySQL: " . $mysqli->connect_error;
    }

    $stmt = $mysqli->prepare("INSERT INTO users (name, age) VALUES (?,?)");

    // insert one row
    $stmt->execute(array('one',1));

    // insert another row with different values
    $stmt->execute(array('two',1));
?>

另外,我是否需要将mysqli用于预处理语句?任何人都能指出我从连接到插入到错误处理选择的准备语句的完整示例吗?

4 个答案:

答案 0 :(得分:9)

FDSA 来自mysqli::prepare docs

  

在执行语句或提取行之前,必须使用mysqli_stmt_bind_param()和/或mysqli_stmt_bind_result()将参数标记绑定到应用程序变量。

bind_param docs

即:

$stmt = $mysqli->prepare("INSERT INTO users (name, age) VALUES (?,?)");

// bind parameters. I'm guessing 'string' & 'integer', but read documentation.
$stmt->bind_param('si','one',1);

// *now* we can execute
$stmt->execute();

答案 1 :(得分:6)

  

我还需要使用mysqli来准备语句。任何人都可以指出一个关于准备语句的完整示例,从连接到插入到选择和错误处理

你也可以使用我更喜欢的PDO。事实上,在您的代码示例中,您似乎混淆了PDO和Mysqli。

$db = new PDO($dsn, $user, $pass);
$stmt = $db->prepare("INSERT INTO users (name, age) VALUES (?,?)");
$stmt->execute(array($name1, $age1));
$stmt->execute(array($name2, $age2));

与mysqli不同,您不必调用单独的绑定功能,但如果您愿意/想要/需要使用它,则可以使用该功能。

关于PDO的另一个有趣的事情是命名占位符,这在复杂查询中可能更少混淆:

$db = new PDO($dsn, $user, $pass);
$stmt = $db->prepare("INSERT INTO users (name, age) VALUES (:name,:age)");
$stmt->execute(array(':name' => $name1, ':age' => $age1));
$stmt->execute(array(':name' => $name2, ':age' => $age2));

答案 2 :(得分:4)

有人能指出我关于从连接到插入再到带有错误处理的选择的准备好的语句的完整示例吗?

这个问题很老,但是直到最近我才完成了一些研究,最终得出了一系列文章,这些文章完全满足了这一要求,所以您可以:

连接

Mysqli连接它是代码的一部分,其重要性经常被忽略,减少到一行。正确的连接代码可以解决从安全到可用性的众多问题。

鉴于您的代码是通常的过程PHP,这是脚本中要包含的简单mysqli连接代码:

$host = '127.0.0.1';
$db   = 'test';
$user = 'root';
$pass = '';
$charset = 'utf8mb4';

mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
try {
    $mysqli = new mysqli($host, $user, $pass, $db);
    $mysqli->set_charset($charset);
} catch (\mysqli_sql_exception $e) {
     throw new \mysqli_sql_exception($e->getMessage(), $e->getCode());
}
unset($host, $db, $user, $pass, $charset); // we don't need them anymore

完整的解释可以在我的文章How to connect properly using mysqli中找到(以及许多有用的提示),但仅举一小部分即可突出显示最重要的部分:

  • 为连接设置正确的字符集将消除整个错误类别,例如怪异的字符/问号而不是数据,空的json_encode()输出,存储表情符号的问题等。
  • 设置适当的错误报告模式将消除mysqli_fetch_assoc()期望参数...等隐秘错误消息/调用成员函数bind_param()...,从而从MySQL提供实际的错误消息。
  • 安全性不是开玩笑的事情,应该没有机会将您的数据库详细信息泄露给外部

插入

Insert query比较简单,其他答案已经涵盖了它。

您所需要做的就是用问号替换查询中的所有变量(以及周围的引号!),然后准备查询,然后将所有变量及其类型推入bind_param()中,最后执行查询。 / p>

一个简单的提示:MySQL会很乐意接受所有变量作为字符串,因此不要费心为某个变量找到正确的类型,只需对任何变量使用“ s”即可。

所以基本上插入会是这样

$sql = "INSERT INTO users (name, email, password) VALUES (?,?,?)";
$stmt= $conn->prepare($sql);
$stmt->bind_param("sss", $name, $email, $password_hash);
$stmt->execute();

对于所有其他查询类型,例如UPDATE或DELETE,应使用相同的原理。

选择

运行select query几乎相同,但是有一个小技巧。由于某些未知的原因,您不能在准备好的语句之后立即使用熟悉的提取函数。因此,您需要先获取 mysqli_result ,然后才能使用fetch_assoc()fetch_obj()等:

$sql = "SELECT * FROM users WHERE id=?"; // SQL with parameters
$stmt = $conn->prepare($sql);
$stmt->bind_param("s", $id);
$stmt->execute();
$result = $stmt->get_result(); // get the mysqli result
$user = $result->fetch_assoc(); // fetch data 

提示:绝对不需要熟悉的mysqli_num_rows()函数。如果考虑到这一点,则始终可以使用数据本身,以查看查询是否返回任何行:

$user = $result->fetch_assoc();
if ($user) {
    // found!
}

多行也一样,这要感谢

另一个提示:有一个方便的功能fetch_all(),可让您一次性找到所有选定行的数组。例如,如果查询返回多行,则可以通过将最后一行更改为

来将它们放入数组
$users = $result->fetch_all(MYSQLI_ASSOC); // fetch data 

错误处理

错误处理是最重要但又有些令人惊讶的部分。尽管有许多文章和示例说了什么,但通常您根本不应该编写任何错误处理代码。这听起来绝对是疯狂的,但这正是必须要做的事情。在大多数情况下,您要做的只是报告错误。 mysqli / PHP已经可以为您完成此任务,不需要帮助。因此,您不应编写任何可验证查询执行结果的代码-如果发生错误,由于#Connection部分中提到的mysqli_report()函数调用,mysqli将自动报告该结果。同样,可以在另一篇专门介绍通用PHP error reporting的文章中找到对该原理的完整说明。

在极少数情况下,您确实需要处理错误时,即在发生错误的情况下执行一些操作,而不仅仅是报告错误,然后包装查询(es)try..catch中。

答案 3 :(得分:-7)

试试这个,清理传入的数据。 不要忘记php标签。

function clean($data)
{ 
  $data = trim(strip_tags(htmlspecialchars($data)));
  return $data;
}

$field1 = isset($_POST['field1']) ? clean($_POST['field1']): NULL;
$field2 = isset($_POST['field2']) ? clean($_POST['field2']): NULL;
$field3 = isset($_POST['field3']) ? clean($_POST['field3']): NULL;
$field4 = isset($_POST['field4']) ? clean($_POST['field4']): NULL;
$field5 = isset($_POST['field5']) ? clean($_POST['field5']): NULL;
$field6 = isset($_POST['field6']) ? clean($_POST['field6']): NULL;
$field7 = isset($_POST['field7']) ? clean($_POST['field7']): NULL;
$database = new mysqli("localhost", "username", "password", "database");
if ($database->errno) die("Error opening database: " . $database->error());
$query = 'INSERT INTO `tablename` (`field1`, `field2`, `field3`, `field4`, `field5`, `field6`, `field7`) VALUES (?, ?, ?, ?, ?, ?, ?)'; 
$result = $database->prepare($query); 
$result->bind_param('sssssss', $field1, $field2, $field3, $field4, $field5, $field6, $field7); 
$result->execute(); 
$database->close();
{
    header("Location: http://www.somewebsite.com");
}