为什么不应该使用mysql_*函数的技术原因是什么?(例如mysql_query()、mysql_connect()或mysql_real_ascape_string())?

为什么我要使用其他东西,即使它们在我的网站上工作?

如果它们在我的网站上不起作用,为什么我会出现这样的错误

警告:mysql_connect():没有这样的文件或目录


当前回答

因为(除其他原因外)要确保输入数据得到净化要困难得多。如果您使用参数化查询,就像使用PDO或mysqli一样,您可以完全避免风险。

例如,有人可以使用“enhzflep);drop table users”作为用户名。旧的函数将允许每个查询执行多个语句,所以像这种讨厌的bug可以删除整个表。

如果要使用mysqli的PDO,用户名将以“enhzflep);drop table user”结尾。

参见bobby-tables.com。

其他回答

因为(除其他原因外)要确保输入数据得到净化要困难得多。如果您使用参数化查询,就像使用PDO或mysqli一样,您可以完全避免风险。

例如,有人可以使用“enhzflep);drop table users”作为用户名。旧的函数将允许每个查询执行多个语句,所以像这种讨厌的bug可以删除整个表。

如果要使用mysqli的PDO,用户名将以“enhzflep);drop table user”结尾。

参见bobby-tables.com。

说到技术原因,只有几个,非常具体,很少使用。很可能你一生中都不会使用它们。也许我太无知了,但我从来没有机会使用它们

非阻塞异步查询返回多个结果集的存储过程加密(SSL)压缩

如果您需要,这些无疑是从mysql扩展转向更时尚、更现代的技术原因。

尽管如此,也有一些非技术性的问题,这会使您的体验更加困难

在现代PHP版本中进一步使用这些函数将引起不推荐使用的级别通知。它们可以简单地关闭。在不久的将来,它们可能会从默认的PHP构建中删除。也没什么大不了的,因为mydsql-ext将被迁移到PECL中,每个宿主都会很乐意用它来编译PHP,因为他们不想失去那些网站工作了几十年的客户。Stackoverflow社区的强烈抵抗。每次你提到这些诚实的功能时,你都会被告知它们是严格的禁忌。作为一个普通的PHP用户,您使用这些函数的想法很可能是错误的。就因为有这么多的教程和手册教你错误的方法。不是函数本身-我必须强调它-而是它们的使用方式。

后一个问题是一个问题。但是,在我看来,提议的解决方案也没有更好。在我看来,所有这些PHP用户都将立即学习如何正确处理SQL查询,这是一个过于理想化的梦想。他们很可能只是机械地将mysql_*更改为mysqli_*,保持方法不变。特别是因为mysqli使准备好的语句使用起来非常痛苦和麻烦。更不用说,本机准备的语句不足以防止SQL注入,mysqli和PDO都没有提供解决方案。

因此,我宁愿反对错误的做法,以正确的方式教育人们,而不是反对这种诚实的延伸。

此外,还有一些错误或不重要的原因,如

不支持存储过程(我们使用的是mysql_query(“CALL my_proc”);年龄)不支持交易(同上)不支持多个语句(谁需要它们?)不在积极发展中(那么,它对你有什么实际影响吗?)缺少OO接口(创建一个OO接口需要几个小时)不支持准备语句或参数化查询

最后一点很有趣。虽然mysql-ext不支持本机准备的语句,但出于安全考虑,它们不是必需的。我们可以使用手动处理的占位符轻松地伪造准备好的语句(就像PDO一样):

function paraQuery()
{
    $args  = func_get_args();
    $query = array_shift($args);
    $query = str_replace("%s","'%s'",$query); 

    foreach ($args as $key => $val)
    {
        $args[$key] = mysql_real_escape_string($val);
    }

    $query  = vsprintf($query, $args);
    $result = mysql_query($query);
    if (!$result)
    {
        throw new Exception(mysql_error()." [$query]");
    }
    return $result;
}

$query  = "SELECT * FROM table where a=%s AND b LIKE %s LIMIT %d";
$result = paraQuery($query, $a, "%$b%", $limit);

瞧,一切都是参数化和安全的。

但好吧,如果你不喜欢手册中的红色框,那么会出现一个选择问题:mysqli还是PDO?

答案如下:

如果您了解使用数据库抽象层并寻找API来创建抽象层的必要性,那么mysqli是一个非常好的选择,因为它确实支持许多mysql特有的特性。如果像绝大多数PHP用户一样,您在应用程序代码中正确使用原始API调用(这基本上是错误的做法),那么PDO是唯一的选择,因为这个扩展假装不仅仅是API,而是一个半DAL,仍然不完整,但提供了许多重要功能,其中两个功能使PDO与mysqli有着重要区别:与mysqli不同,PDO可以通过值绑定占位符,这使得动态构建的查询变得可行,而无需几个屏幕的代码。与mysqli不同,PDO总是可以在一个简单的普通数组中返回查询结果,而mysqli只能在mysqlnd安装上执行。

因此,如果你是一个普通的PHP用户,并且想在使用本机准备的语句时省去一大堆麻烦,那么PDO是唯一的选择。然而,PDO也不是银弹,也有其困难。因此,我为PDO标签wiki中的所有常见陷阱和复杂案例编写了解决方案

然而,每个谈论扩展的人总是忽略了关于Myqli和PDO的两个重要事实:

事先准备好的声明不是灵丹妙药。有一些动态标识符不能使用准备好的语句绑定。存在具有未知数量参数的动态查询,这使得查询构建成为一项困难的任务。mysqli_*和PDO函数都不应该出现在应用程序代码中。在它们和应用程序代码之间应该有一个抽象层,它将在内部完成绑定、循环、错误处理等所有肮脏的工作,使应用程序代码变得干干净净。特别是对于动态查询构建这样的复杂情况。

因此,仅仅切换到PDO或mysqli是不够的。必须使用ORM、查询生成器或任何数据库抽象类,而不是在代码中调用原始API函数。相反,如果在应用程序代码和mysqlAPI之间有一个抽象层,那么使用哪个引擎实际上并不重要。您可以使用mysql-ext,直到它被弃用,然后轻松地将抽象类重写到另一个引擎,使所有应用程序代码保持完整。

下面是基于我的safemysql类的一些示例,以说明这样的抽象类应该是什么样子的:

$city_ids = array(1,2,3);
$cities   = $db->getCol("SELECT name FROM cities WHERE is IN(?a)", $city_ids);

将这一行与PDO所需的代码量进行比较。然后,将您需要的大量代码与原始Myqli准备的语句进行比较。请注意,错误处理、分析和查询日志已经内置并正在运行。

$insert = array('name' => 'John', 'surname' => "O'Hara");
$db->query("INSERT INTO users SET ?u", $insert);

将其与通常的PDO插入进行比较,当每个字段名重复六到十次时,在所有这些众多的命名占位符、绑定和查询定义中。

另一个例子:

$data = $db->getAll("SELECT * FROM goods ORDER BY ?n", $_GET['order']);

您很难找到PDO处理此类实际案例的示例。而且这太啰嗦了,很可能是不安全的。

所以,再一次,你应该关注的不仅仅是原始驱动程序,而是抽象类,它不仅适用于初学者手册中的愚蠢示例,也适用于解决任何现实问题。

不要使用mysql,因为不推荐使用Mysqli。

弃用的含义:

这意味着不要使用某些特定的功能/方法/软件功能/特定的软件实践,这只是意味着不应该使用它,因为该软件中有(或将有)更好的替代方案,而应该使用它。

使用不推荐使用的函数时可能会出现以下几个常见问题:

1.功能完全停止工作:应用程序或脚本可能依赖于不再支持的功能,因此使用其改进版本或替代版本。

2.显示有关弃用的警告消息:这些消息通常不会干扰站点功能。然而,在某些情况下,它们可能会中断服务器发送标头的过程。

例如:这可能会导致登录问题(cookie/会话设置不正确)或转发问题(301/302/303重定向)。

请记住:

-弃用的软件仍然是软件的一部分。

-弃用的代码只是代码的状态(标签)。

MYSQL与MYSQLI的主要区别mysql数据库*

旧数据库驱动程序MySQL只能按程序使用没有针对SQL注入攻击的保护在PHP 5.5.0中被弃用,在PHP 7中被删除

mysqli数据库

新数据库驱动程序当前正在使用准备好的语句可防止攻击

MySQL扩展:

未积极开发自PHP 5.5(2013年6月发布)起正式弃用。自PHP 7.0(2015年12月发布)起已完全删除这意味着截至2018年12月31日,它不存在于任何支持的PHP版本中。如果您使用的是支持它的PHP版本,那么您使用的版本不会解决安全问题。缺少OO接口不支持:非阻塞异步查询准备好的语句或参数化查询存储过程多个语句交易“新”密码身份验证方法(默认情况下,在MySQL 5.6中打开;5.7中需要)MySQL 5.1或更高版本中的任何新功能

由于它已被弃用,因此使用它会使您的代码不那么经得起未来考验。

缺少对准备好的语句的支持尤为重要,因为与使用单独的函数调用手动转义外部数据相比,它们提供了一种更清晰、更不易出错的转义和引用外部数据的方法。

请参阅SQL扩展的比较。

原因有很多,但可能最重要的一点是,这些函数鼓励不安全的编程实践,因为它们不支持准备好的语句。准备好的语句有助于防止SQL注入攻击。

当使用mysql_*函数时,您必须记住通过mysql_real_aescape_string()运行用户提供的参数。如果你只在一个地方忘记了,或者你碰巧只漏掉了部分输入,你的数据库可能会受到攻击。

在PDO或mysqli中使用已准备好的语句将使其更难产生此类编程错误。