后端

PHP mysql_query函数的用法与mysqli_query迁移实践指南

TRAE AI 编程助手

PHP mysql_query函数的用法与mysqli_query迁移实践指南

一、mysql_query函数概述

mysql_query是PHP早期用于执行MySQL查询的核心函数,但由于其存在严重的安全隐患和功能局限性,已在PHP 5.5.0版本中被标记为过时(deprecated),并在PHP 7.0.0版本中被完全移除。

1.1 基本语法

mixed mysql_query ( string $query [, resource $link_identifier = NULL ] )

1.2 主要特点

  • 仅支持同步查询
  • 不支持预处理语句,容易引发SQL注入
  • 错误处理机制不完善
  • 不支持MySQL 4.1以上的新特性
  • 仅支持单一连接
  • 没有面向对象的接口

1.3 典型用法示例

<?php
// 建立连接
$link = mysql_connect('localhost', 'username', 'password');
if (!$link) {
    die('连接失败: ' . mysql_error());
}
 
// 选择数据库
mysql_select_db('test_db', $link);
 
// 执行查询
$result = mysql_query('SELECT * FROM users WHERE id = 1');
 
// 处理结果
if ($result) {
    $row = mysql_fetch_assoc($result);
    echo '用户名: ' . $row['username'];
    
    // 释放结果集
    mysql_free_result($result);
} else {
    die('查询失败: ' . mysql_error());
}
 
// 关闭连接
mysql_close($link);
?>

二、mysql_query的安全隐患

2.1 SQL注入风险

由于mysql_query不支持参数化查询,直接拼接用户输入会导致严重的SQL注入漏洞。

不安全示例:

<?php
$id = $_GET['id']; // 假设用户输入: 1' OR '1'='1
$query = "SELECT * FROM users WHERE id = '$id'";
$result = mysql_query($query); // 实际执行: SELECT * FROM users WHERE id = '1' OR '1'='1'
?>

2.2 错误处理缺陷

mysql_query仅在查询失败时返回FALSE,没有提供详细的错误码和错误信息,不利于问题定位。

2.3 字符集问题

mysql_query依赖mysql_set_charset设置连接字符集,如果未正确设置,可能导致中文乱码问题。

三、mysqli_query函数介绍

mysqli_query是PHP提供的MySQLi扩展中的核心查询函数,是mysql_query的替代方案,支持面向对象和面向过程两种编程风格。

3.1 基本语法

面向过程风格:

mixed mysqli_query ( mysqli $link , string $query [, int $resultmode = MYSQLI_STORE_RESULT ] )

面向对象风格:

mysqli_result mysqli::query ( string $query [, int $resultmode = MYSQLI_STORE_RESULT ] )

3.2 主要特点

  • 支持预处理语句(Prepared Statements)
  • 支持事务处理
  • 支持多语句查询
  • 支持MySQL新特性
  • 完善的错误处理机制
  • 支持面向对象和面向过程两种接口
  • 支持连接池

四、从mysql_query迁移到mysqli_query

4.1 迁移准备

  1. 确保PHP版本在5.5.0以上
  2. 确保已启用MySQLi扩展
  3. 备份原有代码和数据库
  4. 分析原有代码的数据库操作逻辑

4.2 迁移步骤

步骤1:连接数据库的迁移

原mysql_query连接方式:

$link = mysql_connect('localhost', 'username', 'password');
mysql_select_db('test_db', $link);
mysql_set_charset('utf8', $link);

新mysqli_query连接方式:

面向过程:

$mysqli = mysqli_connect('localhost', 'username', 'password', 'test_db');
mysqli_set_charset($mysqli, 'utf8');

面向对象:

$mysqli = new mysqli('localhost', 'username', 'password', 'test_db');
$mysqli->set_charset('utf8');

步骤2:查询执行的迁移

原mysql_query查询方式:

$result = mysql_query('SELECT * FROM users WHERE id = 1');

新mysqli_query查询方式:

面向过程:

$result = mysqli_query($mysqli, 'SELECT * FROM users WHERE id = 1');

面向对象:

$result = $mysqli->query('SELECT * FROM users WHERE id = 1');

步骤3:结果处理的迁移

原mysql_query结果处理:

if ($result) {
    while ($row = mysql_fetch_assoc($result)) {
        echo $row['username'] . '<br>';
    }
    mysql_free_result($result);
}

新mysqli_query结果处理:

面向过程:

if ($result) {
    while ($row = mysqli_fetch_assoc($result)) {
        echo $row['username'] . '<br>';
    }
    mysqli_free_result($result);
}

面向对象:

if ($result) {
    while ($row = $result->fetch_assoc()) {
        echo $row['username'] . '<br>';
    }
    $result->free();
}

步骤4:错误处理的迁移

原mysql_query错误处理:

$result = mysql_query($query);
if (!$result) {
    die('查询失败: ' . mysql_error());
}

新mysqli_query错误处理:

面向过程:

$result = mysqli_query($mysqli, $query);
if (!$result) {
    die('查询失败: ' . mysqli_error($mysqli) . ' (错误码: ' . mysqli_errno($mysqli) . ')');
}

面向对象:

$result = $mysqli->query($query);
if (!$result) {
    die('查询失败: ' . $mysqli->error . ' (错误码: ' . $mysqli->errno . ')');
}

步骤5:安全查询的迁移(使用预处理语句)

原不安全的mysql_query查询:

$username = $_POST['username'];
$password = $_POST['password'];
$query = "SELECT * FROM users WHERE username = '$username' AND password = '$password'";
$result = mysql_query($query);

新的mysqli预处理语句查询:

面向过程:

$stmt = mysqli_prepare($mysqli, "SELECT * FROM users WHERE username = ? AND password = ?");
mysqli_stmt_bind_param($stmt, "ss", $username, $password);
mysqli_stmt_execute($stmt);
$result = mysqli_stmt_get_result($stmt);

面向对象:

$stmt = $mysqli->prepare("SELECT * FROM users WHERE username = ? AND password = ?");
$stmt->bind_param("ss", $username, $password);
$stmt->execute();
$result = $stmt->get_result();

4.3 完整迁移示例对比

原mysql_query完整代码:

<?php
// 建立连接
$link = mysql_connect('localhost', 'root', '123456');
if (!$link) {
    die('连接失败: ' . mysql_error());
}
 
// 选择数据库
mysql_select_db('test_db', $link);
mysql_set_charset('utf8', $link);
 
// 执行查询
$id = $_GET['id'];
$query = "SELECT * FROM users WHERE id = $id";
$result = mysql_query($query);
 
// 处理结果
if ($result) {
    $row = mysql_fetch_assoc($result);
    echo 'ID: ' . $row['id'] . '<br>';
    echo '用户名: ' . $row['username'] . '<br>';
    echo '邮箱: ' . $row['email'] . '<br>';
    
    mysql_free_result($result);
} else {
    die('查询失败: ' . mysql_error());
}
 
// 关闭连接
mysql_close($link);
?>

新mysqli_query完整代码(面向对象):

<?php
// 建立连接
$mysqli = new mysqli('localhost', 'root', '123456', 'test_db');
if ($mysqli->connect_error) {
    die('连接失败: ' . $mysqli->connect_error . ' (错误码: ' . $mysqli->connect_errno . ')');
}
$mysqli->set_charset('utf8');
 
// 执行安全查询
$id = $_GET['id'];
$stmt = $mysqli->prepare("SELECT * FROM users WHERE id = ?");
$stmt->bind_param("i", $id);
$stmt->execute();
$result = $stmt->get_result();
 
// 处理结果
if ($result) {
    $row = $result->fetch_assoc();
    echo 'ID: ' . $row['id'] . '<br>';
    echo '用户名: ' . $row['username'] . '<br>';
    echo '邮箱: ' . $row['email'] . '<br>';
    
    $result->free();
    $stmt->close();
} else {
    die('查询失败: ' . $mysqli->error . ' (错误码: ' . $mysqli->errno . ')');
}
 
// 关闭连接
$mysqli->close();
?>

五、迁移注意事项

5.1 函数名变化

  • mysql_connect → mysqli_connect 或 new mysqli
  • mysql_select_db → 连接时指定数据库或mysqli_select_db
  • mysql_query → mysqli_query 或 $mysqli->query
  • mysql_fetch_assoc → mysqli_fetch_assoc 或 $result->fetch_assoc
  • mysql_error → mysqli_error 或 $mysqli->error
  • mysql_close → mysqli_close 或 $mysqli->close

5.2 参数顺序变化

在面向过程风格中,mysqli函数通常将连接资源作为第一个参数,而mysql函数将连接资源作为可选的最后一个参数。

5.3 结果集处理

mysqli_query默认返回mysqli_result对象(或资源),需要使用相应的mysqli_result方法或函数处理结果。

5.4 错误处理

mysqli提供了更详细的错误信息,包括错误码和错误描述,建议在迁移时完善错误处理机制。

5.5 字符集设置

确保在连接后设置正确的字符集,避免中文乱码问题。

六、总结

mysql_query作为PHP早期的MySQL查询函数,由于其安全性和功能性的局限性,已经被完全淘汰。迁移到mysqli_query不仅可以解决安全问题,还能利用MySQL的新特性和面向对象的编程方式。在迁移过程中,应重点关注连接方式、查询安全和错误处理的变化,特别是要采用预处理语句来防止SQL注入攻击。

(此内容由 AI 辅助生成,仅供参考)