php - PDO ...我做对了吗?

标签 php mysql pdo

老实说,这是我第一次使用PDO和错误异常。我遍历了手册以及过去在这里解决的其他问题,并提出了我非常满意的代码。但是我真的很需要您对此发表意见。我构建了一些通常在项目中经常使用的功能。

请注意,现在我正在做一个测试项目,旨在学习这两个新事物。

首先,我不是OOP的狂热者,并且始终偏向于过程编程类型。

function _database_row($_table, $_id = 0, $_key = "id") {
    global $Database;

    if(is_object($Database)) {
        $Query  =   $Database->prepare("SELECT * FROM {$_table} WHERE {$_key} = :id");
        if($Query->execute(Array(":id" => $_id))) {
            $Query_Data =   $Query->fetchAll(PDO::FETCH_ASSOC);
            if(count($Query_Data)   >=  1) {
                if(count($Query_Data)   ==  1) {
                    return $Query_Data[0];
                }

                return $Query_Data;
            }
        } else {
            throw new Exception("Database Query Failure: ".$Query->errorInfo()[2]);
        }
    }

    return false;
}


上面的函数旨在使用$_table$_id表中获取一行(不一定是整数值)。


请注意,$_id可能(有时)是从$_REQUEST获取的唯一内容(对于此功能)。通过简单地准备语句,我是否可以完全避免任何SQL注入威胁?
我找不到mysql_num_rows()的替代方法(我确实发现很少有PDO方法在查询中使用COUNT()时使用fetchColumn。但是我不喜欢这样,所以我想知道我是否做对了?


还是在人们问之前,让我解释一下,在上面的函数中,我对其进行了设计,因此无论何时我要查找单个行,它都会直接返回该行(当我将“ id”用作$_key时,总是这样,因为它的PRIMARY auto_increment在数据库中),而在极少数情况下,我还需要多个结果:)这似乎很好用,只需要您的意见即可。

使用示例:

_database_row("user", 14); // fetch me the user having id # 14
_database_row("products", 2); // fetch me the user having id # 14
_database_row("products", "enabled", "status"); // fetch me all products with status enabled


...有时在过程编程中,我不会喜欢那些讨厌的“未捕获的异常”错误,相反,我只是喜欢使用bool(false)。所以我这样做是这样的:

function __database_row($_table, $_id = 0, $_key = "id") {
    try {
        return _database_row($_table, $_id, $_key);
    } catch (Exception $e) {
        return false;
    }
}


(不要错过使用另一个前导“ _”)。这似乎也很好,所以您对此有何看法?

重要:


“ PDOStatement :: closeCursor”的用途是什么?我确实读过手册,但是我很困惑,因为我可以随意调用我的函数很多次,但仍能获得期望的/预期的结果,但从未“关闭游标”


现在...足够SELECTSFETCHINGS :)让我们来谈论INSERTS

所以我做了这个功能,可以在一个脚本执行中快速添加多个产品。

function _add_product($_name, $_price = 0) {
    global $Database;

    if(is_object($Database)) {
        $Query  =   $Database->prepare("INSERT INTO products (name, price) VALUES (:name, :price)");
        $Query->execute(Array(":name" => $_name, ":price" => $_price));

        if($Query->rowCount()   >=  1) {    
            return $Database->lastInsertId();
        } else {
            throw new Exception("Database Query Failure: ".$Query->errorInfo()[2]);
        }
    }

    return false;
}


这似乎也可以很好地工作,但是我真的可以依靠我用来获取最新插入ID的方法吗?

谢谢你们!

最佳答案

这里有很多事情,所以我将尝试回答特定的问题并解决一些问题。


  我不是OOP的粉丝


请注意,仅仅因为代码具有对象并不意味着它是面向对象的。您可以以纯粹的过程样式使用PDO,而->的存在并不会使它成为OOP。因此,我不会害怕使用PDO。如果您感觉更好,可以改用程序样式mysqli,但我个人更喜欢PDO。




  通过简单地准备语句,我是否可以完全避免任何SQL注入威胁?


没有。

考虑$pdo->prepare("SELECT * FROM t1 WHERE col1 = $_POST[rightFromUser]")。这是一个准备好的陈述,但仍然容易受到注入的影响。注入漏洞与查询本身有关。如果对语句进行了正确的参数化(例如,您使用的是?而不是$_POST),则您将很容易受到攻击。您的查询:

SELECT * FROM {$_table} WHERE {$_key} = :id


实际上是脆弱的,因为它具有可以注入的变量。尽管查询很容易受到攻击,但这并不一定意味着该代码是存在的。也许您在表名和列名上有一个白名单,并且在调用函数之前先对它们进行检查。但是,查询本身不能移植。我建议完全避免在查询中使用变量-即使对于表/列名称也是如此。不过,这只是一个建议。




  我找不到mysql_num_rows()的替代方法


没有一个。查看获取的结果计数,使用SELECT COUNT或查看表统计信息(对于某些引擎),是获取SELECT语句的列数的肯定方法。请注意,PDOStatement::rowCount确实适用于MySQL的SELECT。但是,不能保证可以使用任何特定于according to the documentation的数据库。我会说我从来没有遇到过使用MySQL获取所选行数的问题。

关于PDO::lastInsertId也有类似的评论。我和MySQL都没有问题。




  让我解释一下,在上面的函数中,我对其进行了设计,因此只要我要查找单个行,它就直接返回该行


我不建议这样做,因为使用该功能时您必须了解此功能。有时可能很方便,但是我认为透明地处理函数的结果会更容易。也就是说,您不必检查返回值即可发现其类型并弄清楚如何处理它。




  我不喜欢那些讨厌的“未捕获的异常”错误


Exception swallowing不好。您应该允许异常传播并适当地处理它们。

通常,除非发生灾难性事件(MySQL错误,无法连接到数据库等),否则不应发生异常,除非在服务器上发生合法事件,否则这些错误在生产中应该很少发生。您可以向用户显示错误页面,但至少要确保记录了异常。在开发过程中,您可能希望异常声音尽可能大,以便您可以准确地确定要调试的内容。

我还认为名称应具有合理的描述性,因此名为__database_row_database_row的两个函数确实令人困惑。




  重要提示:“ PDOStatement :: closeCursor”的用途是什么?


我怀疑您将不得不使用它,因此不必担心太多。本质上,它允许您并行地从单独的准备好的语句中获取。例如:

$stmt1 = $pdo->prepare($query1);
$stmt2 = $pdo->prepare($query2);
$stmt1->execute();
$stmt1->fetch();
// You may need to do this before $stmt2->execute()
$stmt1->closeCursor();
$stmt2->fetch();


我可能是错的,但我认为您不需要为MySQL执行此操作(即您可以在两个语句上都调用execute而不调用closeCursor




  我真的可以依靠我用来获取最新插入ID的方法吗?


PDO关于此(上)的文档似乎比rowCountSELECT更宽容。对于MySQL,我会放心地使用它,但是您始终可以SELECT LAST_INSERT_ID()



我做对了吗?

这是一个很难回答的问题,因为权利的定义可能太多了。显然,您的代码正在运行,并且您正在使用PDO,所以从某种意义上讲。我确实有一些批评:

global $Database;


这将依赖脚本前面的全局$Database变量的声明。相反,您应该将数据库作为参数传递给函数。如果您是OOP爱好者,则还可以使数据库成为具有此功能作为方法的类的属性。通常,您应该避免使用全局状态,因为它会使代码更难以重用和测试。


  上面的函数旨在通过$ _id从$ _table表中获取一行


与其创建通用的查询函数,不如以一种允许您运行用于特定目的的查询的方式设计应用程序,这更好。我真的不明白为什么您要为给定ID选择表的所有列。这没有看起来那么有用。相反,您可能想从这些表中获取特定的列,或者将它们与其他表结合起来以提供特定的功能。

关于php - PDO ...我做对了吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20404867/

相关文章:

mysql - 通配符输入导致其他搜索输入检索多输入搜索表单中的所有数据

php - 带有爆炸/内爆的多术语 SQL 和 PHP PDO

php - 获取类中函数的返回值

php - 使用 phpexcel 从 mysql 数据库创建 excel 报告

php - 如何判断变量是否为空?

php - Magento 尝试设置 session ID 以编程方式添加到购物车

mysql - 从表中找一个至少在这些技术[reactjs, mysql, express] 上工作过的人

php - 推荐系统

php - WordPress url_to_postid 不适用于非默认永久链接

php - 检查数据库中的现有用户名