提问人:JasonDavis 提问时间:9/8/2009 最后编辑:DharmanJasonDavis 更新时间:7/9/2023 访问量:196835
如何将mysql更改为mysqli?
How to change mysql to mysqli?
问:
根据下面我用于常规mysql的代码,如何将其转换为使用mysqli?
是不是像把mysql_query($sql)
改成mysqli_query($sql);
那么简单?
<?PHP
//in my header file that is included on every page I have this
$DB["dbName"] = "emails";
$DB["host"] = "localhost";
$DB["user"] = "root";
$DB["pass"] = "";
$link = mysql_connect($DB['host'], $DB['user'], $DB['pass']) or die("<center>An Internal Error has Occured. Please report following error to the webmaster.<br><br>".mysql_error()."'</center>");
mysql_select_db($DB['dbName']);
// end header connection part
// function from a functions file that I run a mysql query through in any page.
function executeQuery($sql) {
$result = mysql_query($sql);
if (mysql_error()) {
$error = '<BR><center><font size="+1" face="arial" color="red">An Internal Error has Occured.<BR> The error has been recorded for review</font></center><br>';
if ($_SESSION['auto_id'] == 1) {
$sql_formatted = highlight_string(stripslashes($sql), true);
$error .= '<b>The MySQL Syntax Used</b><br>' . $sql_formatted . '<br><br><b>The MySQL Error Returned</b><br>' . mysql_error();
}
die($error);
}
return $result;
}
// example query ran on anypage of the site using executeQuery function
$sql='SELECT auto_id FROM friend_reg_user WHERE auto_id=' .$info['auto_id'];
$result_member=executequery($sql);
if($line_member=mysql_fetch_array($result_member)){
extract($line_member);
} else {
header("location: index.php");
exit;
}
?>
答:
我暂时建议使用 PDO 进行 SQL 访问。
然后,只需更改驱动程序并确保SQL在新后端上工作即可。理论上。数据迁移是一个不同的问题。
抽象数据库访问很棒。
首先要做的可能是将每个函数调用替换为其等效项,至少如果您愿意使用过程式 API——考虑到您已经有一些基于 MySQL API 的代码,这将是更简单的方法,这是一个过程式 API。mysql_*
mysqli_*
为了帮助解决这个问题,MySQLi扩展函数摘要绝对是有帮助的。
例如:
mysql_connect
将被替换为mysqli_connect
mysql_error
将替换为mysqli_error
和/或mysqli_connect_error
,具体取决于上下文mysql_query
将被替换为mysqli_query
- 等等
注意:对于某些函数,您可能需要仔细检查参数: 也许这里和那里有一些差异 - 但不是那么多,我会说:mysql和mysqli都基于同一个库(libmysql;至少对于PHP <= 5.2)
例如:
- 对于MySQL,您必须在连接后使用
mysql_select_db
来指示要在哪个数据库上进行查询 - 另一方面,MySQLI允许您将该数据库名称指定为
要mysqli_connect
的第四个参数。 - 不过,如果您愿意,还可以使用一个
mysqli_select_db
功能。
完成此操作后,尝试执行脚本的新版本...并检查一切是否正常;如果不是...是时候寻找虫子了;-)
评论
mysqli_*
mysql_*(q, link, ...)
mysqli_*(link, q, ...)
(我意识到这很旧,但它仍然会出现......
如果确实替换为 ,请记住,整个函数负载需要传递数据库链接。mysql_*
mysqli_*
mysqli_*
例如:
mysql_query($query)
成为
mysqli_query($link, $query)
即,需要大量检查。
评论
我总是处理这个的最简单方法
$con = mysqli_connect($serverName,$dbusername,$dbpassword);
3 步更换,顺序如下
- 所有 “mysql_select_db(” 与 “mysqli_select_db($con,"
- 所有带有“mysqli_query($con”的“mysql_query(”)和
- 所有“mysql_”都带有“mysqli_”。
这每次都对我有用
评论
function
global $con;
$con
如果你的项目中有很多文件要更改,你可以创建同名的函数,比如 mysql 函数, 并在函数中进行转换,如下代码所示:
$sql_host = "your host";
$sql_username = "username";
$sql_password = "password";
$sql_database = "database";
$mysqli = new mysqli($sql_host , $sql_username , $sql_password , $sql_database );
/* check connection */
if ($mysqli->connect_errno) {
printf("Connect failed: %s\n", $mysqli->connect_error);
exit();
}
function mysql_query($query){
$result = $mysqli->query($query);
return $result;
}
function mysql_fetch_array($result){
if($result){
$row = $result->fetch_assoc();
return $row;
}
}
function mysql_num_rows($result){
if($result){
$row_cnt = $result->num_rows;;
return $row_cnt;
}
}
如果是大型项目,需要更改许多文件,并且如果PHP的先前项目版本是5.6,而新的项目版本是7.1,则可以创建一个新文件sql.php并将其包含在标题中或您一直使用它并需要sql连接的地方。例如:
//local
$sql_host = "localhost";
$sql_username = "root";
$sql_password = "";
$sql_database = "db";
$mysqli = new mysqli($sql_host , $sql_username , $sql_password , $sql_database );
/* check connection */
if ($mysqli->connect_errno) {
printf("Connect failed: %s\n", $mysqli->connect_error);
exit();
}
// /* change character set to utf8 */
if (!$mysqli->set_charset("utf8")) {
printf("Error loading character set utf8: %s\n", $mysqli->error);
exit();
} else {
// printf("Current character set: %s\n", $mysqli->character_set_name());
}
if (!function_exists('mysql_real_escape_string')) {
function mysql_real_escape_string($string){
global $mysqli;
if($string){
// $mysqli = new mysqli($sql_host , $sql_username , $sql_password , $sql_database );
$newString = $mysqli->real_escape_string($string);
return $newString;
}
}
}
// $mysqli->close();
$conn = null;
if (!function_exists('mysql_query')) {
function mysql_query($query) {
global $mysqli;
// echo "DAAAAA";
if($query) {
$result = $mysqli->query($query);
return $result;
}
}
}
else {
$conn=mysql_connect($sql_host,$sql_username, $sql_password);
mysql_set_charset("utf8", $conn);
mysql_select_db($sql_database);
}
if (!function_exists('mysql_fetch_array')) {
function mysql_fetch_array($result){
if($result){
$row = $result->fetch_assoc();
return $row;
}
}
}
if (!function_exists('mysql_num_rows')) {
function mysql_num_rows($result){
if($result){
$row_cnt = $result->num_rows;;
return $row_cnt;
}
}
}
if (!function_exists('mysql_free_result')) {
function mysql_free_result($result){
if($result){
global $mysqli;
$result->free();
}
}
}
if (!function_exists('mysql_data_seek')) {
function mysql_data_seek($result, $offset){
if($result){
global $mysqli;
return $result->data_seek($offset);
}
}
}
if (!function_exists('mysql_close')) {
function mysql_close(){
global $mysqli;
return $mysqli->close();
}
}
if (!function_exists('mysql_insert_id')) {
function mysql_insert_id(){
global $mysqli;
$lastInsertId = $mysqli->insert_id;
return $lastInsertId;
}
}
if (!function_exists('mysql_error')) {
function mysql_error(){
global $mysqli;
$error = $mysqli->error;
return $error;
}
}
评论
这里有一个完整的教程,如果你需要在PHP升级后再次使worgking成为一个网站,如何快速制作它。在将客户的托管从 5.4 (OMG!!) 升级到 7.x PHP 版本后,我使用了它。
这是一种解决方法,最好使用 PDO 或 mysqli 类。
1. 连接定义
首先,您需要将连接放在一个新变量或 ,或任何你想要的东西上。$link
$con
例
将连接从 :
@mysql_connect($host, $username, $password) or die("Error message...");
@mysql_select_db($db);
或
@mysql_connect($host, $username, $password, $db) or die("Error message...");
自:
$con = mysqli_connect($host, $username, $password, $db) or die("Error message...");
2. mysql_*修改
使用Notepad ++,我使用“在文件中查找”(Ctrl + Shift + f):
按以下顺序排列我选择“在文件中替换”:
mysql_query( -> mysqli_query($con,
mysql_error() -> mysqli_error($con)
mysql_close() -> mysqli_close($con)
mysql_insert_id() -> mysqli_insert_id($con)
mysql_real_escape_string( -> mysqli_real_escape_string($con,
mysql_ -> mysqli_
3. 调整
如果您遇到错误,可能是因为您的$con无法从您的函数访问。
您需要在所有函数中添加 a,例如:global $con;
function my_function(...) {
global $con;
...
}
在 SQL 类中,您将把 connection 放在 而不是 .并在每个函数调用中替换它(例如:$this->con
$con
mysqli_query($con, $query);
)
评论
将函数升级到 MySQLi API 的终极指南mysql_*
新的mysqli扩展的原因是为了利用MySQL系统版本4.1.3和更新版本中的新功能。将现有代码从 mysqli API 更改为mysqli API时,应利用这些改进,否则升级工作可能会徒劳无功。
mysqli 扩展具有许多优点,与 mysql 扩展相比的主要增强功能是:mysql_*
- 面向对象的界面
- 支持预准备语句
- 增强的调试功能
从函数升级到MySQLi时,重要的是要考虑这些功能,以及此API使用方式的一些变化。mysql_*
1. 面向对象的接口与过程函数。
新的 mysqli 面向对象的界面是对旧函数的重大改进,它可以使您的代码更简洁,更不容易受到印刷错误的影响。还有此 API 的过程版本,但不鼓励使用它,因为它会导致代码的可读性降低,从而更容易出错。
要使用 MySQLi 打开与数据库的新连接,您需要创建 MySQLi 类的新实例。
$mysqli = new \mysqli($host, $user, $password, $dbName);
$mysqli->set_charset('utf8mb4');
使用程序样式,它看起来像这样:
$mysqli = mysqli_connect($host, $user, $password, $dbName);
mysqli_set_charset($mysqli, 'utf8mb4');
请记住,只有前 3 个参数与 中的参数相同。旧 API 中的相同代码为:mysql_connect
$link = mysql_connect($host, $user, $password);
mysql_select_db($dbName, $link);
mysql_query('SET NAMES utf8');
如果您的 PHP 代码依赖于具有 php.ini 中定义的默认参数的隐式连接,则现在必须打开传递代码中参数的 MySQLi 连接,然后提供指向所有过程函数的连接链接或使用 OOP 样式。
有关更多信息,请参阅文章:如何使用 mysqli 正确连接
2. 对准备好的语句的支持
这是一个大问题。MySQL在MySQL 4.1(2004)中添加了对本机预准备语句的支持。预准备语句是防止 SQL 注入的最佳方法。在 PHP 中添加对本机预准备语句的支持是合乎逻辑的。每当数据需要与 SQL 语句一起传递时(即 ,或者是通常的用例),就应该使用预准备语句。WHERE
INSERT
UPDATE
旧的MySQL API有一个函数可以转义SQL中使用的字符串,称为mysql_real_escape_string
,但它从来都不是为了防止SQL注入,自然不应该用于此目的。
新的MySQLi API提供了mysqli_real_escape_string
向后兼容性的替代函数,该函数存在与旧API相同的问题,因此除非准备好的语句不可用,否则不应使用。
旧的 mysql_* 方式:
$login = mysql_real_escape_string($_POST['login']);
$result = mysql_query("SELECT * FROM users WHERE user='$login'");
准备的语句方式:
$stmt = $mysqli->prepare('SELECT * FROM users WHERE user=?');
$stmt->bind_param('s', $_POST['login']);
$stmt->execute();
$result = $stmt->get_result();
MySQLi 中的准备好的语句对于初学者来说可能看起来有点令人反感。如果您要开始一个新项目,那么决定使用更强大、更简单的 PDO API 可能是一个好主意。
3. 增强的调试能力
一些老式的PHP开发人员习惯于手动检查SQL错误,并直接在浏览器中显示它们作为调试手段。然而,事实证明,这种做法不仅繁琐,而且存在安全风险。值得庆幸的是,MySQLi改进了错误报告功能。
MySQLi 能够将遇到的任何错误报告为 PHP 异常。PHP 异常会在脚本中冒泡,如果不处理,将立即终止它,这意味着在错误之后的任何语句都不会被执行。该异常将触发 PHP 致命错误,并将表现为从 PHP 核心触发的任何错误,遵循 和 设置。要启用 MySQLi 例外,请在打开数据库连接之前使用该行并插入该行。display_errors
log_errors
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT)
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$mysqli = new \mysqli($host, $user, $password, $dbName);
$mysqli->set_charset('utf8mb4');
如果您习惯于编写以下代码:
$result = mysql_query('SELECT * WHERE 1=1');
if (!$result) {
die('Invalid query: ' . mysql_error());
}
或
$result = mysql_query('SELECT * WHERE 1=1') or die(mysql_error());
您不再需要在代码中这样做。die()
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$mysqli = new \mysqli($host, $user, $password, $dbName);
$mysqli->set_charset('utf8mb4');
$result = $mysqli->query('SELECT * FROM non_existent_table');
// The following line will never be executed due to the mysqli_sql_exception being thrown above
foreach ($result as $row) {
// ...
}
如果由于某种原因您不能使用异常,MySQLi具有用于错误检索的等效函数。您可以使用它来检查连接错误和任何其他错误。注意 OOP 中的强制参数,或者坚持 OOP 样式并使用 。mysqli_connect_error()
mysqli_error($mysqli)
mysqli_error($mysqli)
$mysqli->error
$result = $mysqli->query('SELECT * FROM non_existent_table') or trigger_error($mysqli->error, E_USER_ERROR);
有关更多解释,请参阅以下帖子:
mysqli 或 die,它必须死吗?
如何获取不同环境下的MySQLi错误信息?
4. 其他变更
不幸的是,并非每个函数在MySQLi中都有其对应项,只是在名称和连接链接中添加了“i”作为第一个参数。以下是其中的一些列表:mysql_*
mysql_client_encoding()
已替换为mysqli_character_set_name($mysqli)
mysql_create_db
没有对应物。使用预准备语句或改用mysqli_query
mysql_drop_db
没有对应物。使用预准备语句或改用mysqli_query
mysql_db_name
&mysql_list_dbs
支持已放弃,转而支持 SQL 的SHOW DATABASES
mysql_list_tables
支持已放弃,转而支持 SQL 的SHOW TABLES FROM dbname
mysql_list_fields
支持已放弃,转而支持 SQL 的SHOW COLUMNS FROM sometable
mysql_db_query
->然后使用查询或在查询中指定数据库名称mysqli_select_db()
mysql_fetch_field($result, 5)
-> 中不存在第二个参数(偏移量)。您可以使用牢记返回的不同结果mysqli_fetch_field
mysqli_fetch_field_direct
mysql_field_flags
、 、 和 -> 已替换为mysql_field_len
mysql_field_name
mysql_field_table
mysql_field_type
mysqli_fetch_field_direct
mysql_list_processes
已被删除。如果需要线程 ID,请使用mysqli_thread_id
mysql_pconnect
已替换为 with host prefixmysqli_connect()
p:
mysql_result
-> 与 和 结合使用mysqli_data_seek()
mysqli_field_seek()
mysqli_fetch_field()
mysql_tablename
支持已放弃,转而支持 SQL 的SHOW TABLES
mysql_unbuffered_query
已被删除。有关详细信息,请参阅此文章 缓冲查询和无缓冲查询
评论
mysql_set_charset
虽然这个话题已经有十年的历史了,但我仍然经常需要“反向修补”依赖于扩展的现有应用程序——最初的程序员懒得重构他们所有的代码,只是告诉客户确保他们运行最新的 PHP 5.6 版本。mysql
PHP 5.6 现已正式弃用;换句话说,开发人员有十年的时间来摆脱他们的依赖并转向(或者,好吧,......但。。。更改如此多的遗留代码是昂贵的,而且并不是每个经理都愿意为“修复”数十万行的项目支付无数小时的费用。mysql
PDO
mysqli
我搜索过许多解决方案,就我而言,我经常使用 @esty-shlomovitz 提出的解决方案——但与此同时,我发现了更好的东西:
https://www.phpclasses.org/package/9199-PHP-Replace-mysql-functions-using-the-mysqli-extension.html
(您需要注册才能下载它,但这只需要一分钟)
这些只是两个文件,它们充当整个扩展的直接替代品,并且非常巧妙地模拟几乎所有内容(使用),而无需担心太多。当然,这不是一个完美的解决方案,但它很可能在 99% 的所有情况下都有效。mysql
mysqli
此外,还可以在此处找到处理迁移琐事的好教程(列出迁移时的许多常见陷阱):https://www.phpclasses.org/blog/package/9199/post/3-Smoothly-Migrate-your-PHP-Code-using-the-Old-MySQL-extension-to-MySQLi.html
(如果你在 2030 年阅读这篇文章并且 PHPclasses 网站已经关闭,那么你可以随时尝试 archive.org :-)
更新:@crashwap下面的评论中指出,您也可以直接从 GitHub 获取相同的代码。谢谢你的提示,@crashwap :-)
评论
include()
我刚刚创建了具有相同名称的函数来转换并覆盖到新的php7:
$host = "your host";
$un = "username";
$pw = "password";
$db = "database";
$MYSQLI_CONNECT = mysqli_connect($host, $un, $pw, $db);
function mysql_query($q) {
global $MYSQLI_CONNECT;
return mysqli_query($MYSQLI_CONNECT,$q);
}
function mysql_fetch_assoc($q) {
return mysqli_fetch_assoc($q);
}
function mysql_fetch_array($q){
return mysqli_fetch_array($q , MYSQLI_BOTH);
}
function mysql_num_rows($q){
return mysqli_num_rows($q);
}
function mysql_insert_id() {
global $MYSQLI_CONNECT;
return mysqli_insert_id($MYSQLI_CONNECT);
}
function mysql_real_escape_string($q) {
global $MYSQLI_CONNECT;
return mysqli_real_escape_string($MYSQLI_CONNECT,$q);
}
它对我有用,我希望它对你们都有用,如果我弄错了,请纠正我。
2020+ 回答
我创建了一个名为 Rector 的工具,用于处理即时升级。还有 mysql → mysqli 集。
它处理:
函数重命名
不断重命名
切换参数
非 1:1 函数调用更改,例如
$data = mysql_db_name($result, $row);
↓
mysqli_data_seek($result, $row); $fetch = mysql_fetch_row($result); $data = $fetch[0];
如何使用 Rector?
1.通过Composer安装它
composer require rector/rector --dev
2. 在项目根目录中创建,并设置 Mysql to Mysqlirector.php
<?php
use Rector\Set\ValueObject\SetList;
use Rector\Config\RectorConfig;
return static function (RectorConfig $rectorConfig): void {
$rectorConfig->sets([
SetList::MYSQL_TO_MYSQLI,
]);
};
3. 让 Rector 在 /src 目录上运行,以仅显示差异
vendor/bin/rector process src --dry-run
4. 让 Rector 更改代码
vendor/bin/rector process src
我已经在 2 个大型 PHP 项目上运行了它,并且运行良好。
评论
The "--set" option does not exist.
rector.php
与 DHW 的答案类似,但您不必担心在所有函数中将链接设置为全局链接,因为这有点困难:
只需在配置文件中使用以下代码:
$sv_connection = mysqli_connect($dbhost, $dbuser, $dbpass, $dbname);
$db_connection = mysqli_select_db ($sv_connection, $dbname);
mysqli_set_charset($sv_connection, 'utf8'); //optional
// Check connection
if (mysqli_connect_errno()) {
echo "Failed to connect to MySQL: " . mysqli_connect_error();
exit();
}
function mysqljx_query($q){
global $sv_connection;
return mysqli_query($sv_connection, $q);
}
function mysqljx_fetch_array($r){
return mysqli_fetch_array($r);
}
function mysqljx_fetch_assoc($r){
return mysqli_fetch_assoc($r);
}
function mysqljx_num_rows($r){
return mysqli_num_rows($r);
}
function mysqljx_insert_id(){
global $sv_connection;
return mysqli_insert_id($sv_connection);
}
function mysqljx_real_escape_string($string){
global $sv_connection;
return mysqli_real_escape_string($sv_connection, $string);
}
- 现在搜索包含“mysql_”的 php 文件(我为此使用了 total commander - Alt+F7,搜索“*.php”,找到文本“mysql_”,开始搜索,馈送到列表框)
- 将它们全部拖放到记事本++中,然后按CTRL + H,查找内容:“mysql_”,替换为“mysqljx_”,“替换所有打开的文档中的所有文档”
如果您担心自己有上面列出的其他功能,只需一个接一个地替换(“mysql_query”替换为“mysqljx_query”,然后mysql_fetch_array替换为“mysqljx_fetch_array”等),然后再次搜索“mysql_”,如果它仍然存在,它是一个未覆盖的功能,您可以添加它与其余功能相同。
就是这样
评论