如何将mysql更改为mysqli?

Jas*_*vis 53 php mysql 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;
}
?>
Run Code Online (Sandbox Code Playgroud)

Pas*_*TIN 72

要做的第一件事可能是mysql_*用等效的方法替换每个函数调用mysqli_*,至少如果你愿意使用过程API - 这将是更简单的方法,考虑到你已经有一些基于MySQL API的代码,是程序性的.

为了解决这个问题,MySQLi扩展函数摘要绝对是有用的.

例如:

请注意,对于某些函数,您可能需要仔细检查参数:也许这里和那里存在一些差异 - 但不是很多,我会说:mysql和mysqli都基于相同的库(libmysql; at至少对于PHP <= 5.2)

例如:

  • 使用mysql,您必须使用mysql_select_db一次连接,以指示您要在哪个数据库上进行查询
  • 另一方面,mysqli允许您将该数据库名称指定为第四个参数mysqli_connect.
  • mysqli_select_db如果您愿意,还可以使用一种功能.


完成后,尝试执行脚本的新版本...并检查一切是否正常; 如果不是......寻找漏洞的时间;-)

  • 有一些工具可以自动完成迁移过程,例如:https://github.com/philip/MySQLConverterTool (4认同)
  • 注意,某些“ mysqli_ *”过程函数的前两个参数已切换。旧样式为mysql _ *(q,link,...),新样式为mysqli _ *(link,q,...)。 (2认同)
  • 尽管这是公认的答案,并回答了*问题*,但它没有提到这样的转换仍然会让您面临严重的 SQLi 安全漏洞(由于缺乏准备好的语句)。我建议参考 [*官方 PHP 文档*](https://www.php.net/manual/en/mysqli.quickstart.prepared-statements.php) 在 PHP 中使用准备好的语句。 (2认同)

小智 31

(我意识到这是旧的,但它仍然出现......)

如果你确实替换mysql_*,mysqli_*那么请记住,一大堆mysqli_*函数需要传递数据库链接.

例如:

mysql_query($query)
Run Code Online (Sandbox Code Playgroud)

mysqli_query($link, $query)
Run Code Online (Sandbox Code Playgroud)

即,需要进行大量检查.

  • **对于未来的读者:** 不要停止阅读,直到您看到下面 2019 年 7 月的 [Dharmans 答案](/sf/answers/3989851701/)。**这**应该是这个问题的公认答案,恕我直言。 (2认同)

Dha*_*man 22

mysql_*功能升级到 MySQLi API的终极指南

新的 mysqli 扩展的原因是利用 MySQL 系统版本 4.1.3 和更新版本中的新功能。将现有代码从mysql_*mysqli API更改为 mysqli API 时,您应该利用这些改进,否则您的升级工作可能会白费。
mysqli 扩展有很多好处,对 mysql 扩展的主要增强是:

  • 面向对象的接口
  • 支持准备好的报表
  • 增强的调试功能

当从mysql_*函数升级到 MySQLi 时,重要的是要考虑这些特性,以及这个 API 应该使用的方式的一些变化。

1. 面向对象的接口与过程函数。

新的 mysqli 面向对象接口是对旧函数的重大改进,它可以使您的代码更干净,并且不易受排版错误的影响。还有这个 API 的过程版本,但不鼓励使用它,因为它会导致代码可读性降低,更容易出错。

要使用 MySQLi 打开与数据库的新连接,您需要创建 MySQLi 类的新实例。

$mysqli = new \mysqli($host, $user, $password, $dbName);
$mysqli->set_charset('utf8mb4');
Run Code Online (Sandbox Code Playgroud)

使用程序风格,它看起来像这样:

$mysqli = mysqli_connect($host, $user, $password, $dbName);
mysqli_set_charset($mysqli, 'utf8mb4');
Run Code Online (Sandbox Code Playgroud)

请记住,只有前 3 个参数与mysql_connect. 旧 API 中的相同代码是:

$link = mysql_connect($host, $user, $password);
mysql_select_db($dbName, $link);
mysql_query('SET NAMES utf8');
Run Code Online (Sandbox Code Playgroud)

如果您的 PHP 代码依赖于 php.ini 中定义的默认参数的隐式连接,那么您现在必须打开 MySQLi 连接并在您的代码中传递参数,然后提供所有过程函数的连接链接或使用 OOP 样式。

有关更多信息,请参阅文章:如何使用 mysqli 正确连接

2. 支持准备好的报表

这是一个很大的。MySQL 在 MySQL 4.1 (2004) 中添加了对原生预准备语句的支持。准备好的语句是防止 SQL 注入的最好方法。对原生准备好的语句的支持被添加到 PHP 中是合乎逻辑的。只要数据需要与 SQL 语句一起传递(即WHEREINSERT或者UPDATE是通常的用例),就应该使用准备好的语句。

旧的 MySQL API 有一个函数来转义 SQL 中使用的字符串,称为mysql_real_escape_string,但它从来没有用于防止 SQL 注入,自然不应该用于此目的。
新的 MySQLi APImysqli_real_escape_string为向后兼容性提供了一个替代功能,它与旧的存在相同的问题,因此除非准备好的语句不可用,否则不应使用。

旧的 mysql_* 方式:

$login = mysql_real_escape_string($_POST['login']);
$result = mysql_query("SELECT * FROM users WHERE user='$login'");
Run Code Online (Sandbox Code Playgroud)

准备好的语句方式:

$stmt = $mysqli->prepare('SELECT * FROM users WHERE user=?');
$stmt->bind_param('s', $_POST['login']);
$stmt->execute();
$result = $stmt->get_result();
Run Code Online (Sandbox Code Playgroud)

MySQLi 中的预处理语句对于初学者来说可能看起来有点令人反感。如果您正在开始一个新项目,那么决定使用更强大、更简单的PDO API 可能是个好主意。

3. 增强的调试能力

一些老派的 PHP 开发人员习惯于手动检查 SQL 错误并将它们直接显示在浏览器中作为调试的手段。但事实证明,这种做法不仅繁琐,而且存在安全隐患。幸运的是 MySQLi 改进了错误报告功能。

MySQLi 能够将它遇到的任何错误报告为 PHP 异常。PHP 异常会在脚本中冒泡,如果未处理将立即终止它,这意味着在错误之后不会执行任何语句。该异常将触发 PHP 致命错误,并将表现为任何由 PHP 核心触发的错误,并遵循display_errorslog_errors设置。要启用 MySQLi 异常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');
Run Code Online (Sandbox Code Playgroud)

如果您习惯于编写代码,例如:

$result = mysql_query('SELECT * WHERE 1=1');
if (!$result) {
    die('Invalid query: ' . mysql_error());
}
Run Code Online (Sandbox Code Playgroud)

或者

$result = mysql_query('SELECT * WHERE 1=1') or die(mysql_error());
Run Code Online (Sandbox Code Playgroud)

你不再需要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) {
    // ...
}
Run Code Online (Sandbox Code Playgroud)

如果由于某种原因您不能使用异常,MySQLi 具有等效的错误检索功能。您可以使用mysqli_connect_error()来检查连接错误和mysqli_error($mysqli)任何其他错误。注意强制参数mysqli_error($mysqli)或坚持 OOP 风格并使用$mysqli->error.

$result = $mysqli->query('SELECT * FROM non_existent_table') or trigger_error($mysqli->error, E_USER_ERROR);
Run Code Online (Sandbox Code Playgroud)

更多解释请看这些帖子:
mysqli or die,do it have to die?
不同环境下如何获取MySQLi错误信息?

4. 其他变化

不幸的是,并不是每个函数mysql_*在 MySQLi 中都有对应的函数,只是在名称和连接链接中添加了一个“i”作为第一个参数。以下是其中一些的列表:

  • mysql_client_encoding() 已被替换 mysqli_character_set_name($mysqli)
  • mysql_create_db没有对应物。使用准备好的语句或mysqli_query代替
  • mysql_drop_db没有对应物。使用准备好的语句或mysqli_query代替
  • mysql_db_name&mysql_list_dbs支持已被删除,转而支持 SQLSHOW 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已被替换mysqli_connect()p:主机前缀
  • mysql_result->mysqli_data_seek()mysqli_field_seek()和结合使用mysqli_fetch_field()
  • mysql_tablename 支持已被删除,转而支持 SQL SHOW TABLES
  • mysql_unbuffered_query已被删除。有关缓冲和非缓冲查询的更多信息,请参阅本文

  • 精彩的答案 - 但没有得到足够的支持。我将查看您的其他答案,看看您还做了哪些出色且值得点赞的事情。非常感谢您在这个问题上花费的时间和精力。 (3认同)
  • 答案是一个很好的惊喜,因为对于这类问题,你期待的是一个无用的脱离循环的评论。相信会得到应有的认可。只是一些挑剔。还有 mysql_set_charset(),只是一个事实检查;我不会责怪mres()“不足以防止SQL注入”。你不能责怪斧头没有锯你的原木。所以我宁愿把它说成“它从来不是为了保护而自然不应该被用于这个目的” (2认同)

小智 15

我总是处理这个最简单的方法

其中$ con = mysqli_connect($ serverName,$ dbusername,$ dbpassword);

按以下顺序更换3个步骤

  1. 所有" mysql_select_db( "with" mysqli_select_db($ con, ")
  2. 所有" mysql_query( "with" mysqli_query($ con, "and
  3. 所有" mysql_ "都带有" mysqli_ ".

这对我来说每次都适用

  • 我将添加搜索所有`function`字符串并在函数内容之上放置一个`global $ con;`,因为函数外部定义的`$ con`默认情况下不可用,因为PHP中的变量范围. (3认同)

Tom*_*uba 14

2020+ 答案

我创建了一个名为 Rector的工具,用于处理即时升级。还有mysql吗?mysqli设置

它处理:

如何使用校长?

1. 通过 Composer 安装

composer require rector/rector --dev

// or in case of composer conflicts
composer require rector/rector-prefixed --dev
Run Code Online (Sandbox Code Playgroud)

2.rector.php在项目根目录下创建Mysql转Mysqli设置

<?php

use Rector\Core\Configuration\Option;
use Rector\Set\ValueObject\SetList;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;

return static function (ContainerConfigurator $containerConfigurator): void {

    $parameters->set(Option::SETS, [
        SetList::MYSQL_TO_MYSQLI,
    ]);
};
Run Code Online (Sandbox Code Playgroud)

3. 让 Rector 在 /src 目录上运行以仅显示差异

vendor/bin/rector process src --dry-run
Run Code Online (Sandbox Code Playgroud)

4.让Rector改代码

vendor/bin/rector process src
Run Code Online (Sandbox Code Playgroud)

我已经在 2 个大型 PHP 项目上运行过它,并且运行良好。

  • 它是否启用 mysqli 错误报告并且是否切换到带有参数绑定的准备好的语句? (2认同)
  • 经过一些小的改变,效果很好。首先,从源目录运行它,而不是 PHP 可执行文件目录。其次,指定 ector 目录的完整路径。第三,这里指定的php少了一行。在使用之前先定义$parameters,$parameters = $containerConfigurator-&gt;parameters(); (2认同)
  • 目前,rector 1.0 中没有这样的设置`MYSQL_TO_MYSQLI` – (2认同)

Aid*_*ell 6

我会暂时建议使用PDO进行SQL访问。

然后,只有更改驱动程序并确保SQL在新的后端上正常工作的情况。理论上。数据迁移是另一个问题。

抽象数据库访问很棒。


小智 5

对于大型项目,需要更改许多文件,并且如果以前的PHP项目版本为5.6,而新的PHP版本为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;
    }
}
Run Code Online (Sandbox Code Playgroud)