lastinsertId() 在与 exec() 一起工作时不能与 execute() 一起工作?

Posted

技术标签:

【中文标题】lastinsertId() 在与 exec() 一起工作时不能与 execute() 一起工作?【英文标题】:lastinsertId() not working with execute() while it works with exec()? 【发布时间】:2017-08-31 21:21:52 【问题描述】:

这是我完整的 php 代码,除了只包含服务器信息的配置文件。此代码在使用准备时通过执行错误来防止 sql 注入并且不返回 lastinserted id。有没有办法通过准备语句并同时返回最后插入的id来防止sql注入。

<?php
$root = dirname(dirname(__FILE__));
require_once "$root/core/config/config.php";
class engine 
//constructing database connection based on configuration parameters 
function __construct() 

    if(DB_SERVER!="" && DB_USERNAME!="" && DB_PASSWORD!="" && DB_NAME!="") 
        try 
            $this->conn = new PDO('mysql:host='.DB_SERVER.'; dbname='.DB_NAME, DB_USERNAME, DB_PASSWORD);
            //$this->conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT); PDO::ERRMODE_EXCEPTION for testing db errors
            $this->conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
         
        catch(PDOException $e) 
            echo 'ERROR: ' . $e->getMessage();
        
     else 
        $url = pathinfo($_SERVER["PHP_SELF"], PATHINFO_DIRNAME) . "/" . $path;
        $url = preg_replace("/\/\/+/", "/", $url);
        $url = "http://" . $_SERVER["SERVER_NAME"] . $url;
        die("no database login");
    
   

这里出现问题,如果我在执行前准备语句,它不会返回 lastinsertid。通过一个错误lastinsertid方法报错

//function to insert data in given table
public function insert($postcol, $postval, $table)
    $sql="INSERT INTO ".$table;
    $sql.=" ".$postcol;
    $sql.=" VALUES ".$postval;
    $stmt = $this->conn->prepare($sql);
    $stmt->execute();
    $lastid = $stmt->lastInsertId();
    return($lastid);

如果上面的函数改为直接执行,它可以正常工作,如下所示

//function to insert data in given table
public function insert($postcol, $postval, $table)
    $sql="INSERT INTO ".$table;
    $sql.=" ".$postcol;
    $sql.=" VALUES ".$postval;
    $stmt = $this->conn->exec($sql);
    $lastid = $stmt->lastInsertId();
    return($lastid);

下面的代码是剥离输入并将数据转发到插入函数

public function formpro($post,$table,$action)
    switch($action)        
        case "insert" :     
        $numItems = count($post);
        $i = 0;
        $col="(";
        $val="(";
        foreach($post as $key=>$value) 
          if(++$i != $numItems) 
            $col.="`".$key."`, ";
            if(is_numeric($val))
                $val.=$value.", ";
            
            else
            $val.="'".$value."', ";
                
          
          else
            $col.="`".$key."`";
             if(is_numeric($val))
                $val.=$value;
            
            else
            $val.="'".$value."'";
                
          
        
        $col.=")";
        $val.=")";
        return(engine::insert($col,$val,$table));
    


//to check class worked following data processed
$arr=array("user_name"=>"addya", "full_name"=>"ananda bhat", "password"=>"fattos", "rank"=>"3");
$engine=new engine();
echo($engine->formpro($arr,"users","insert"));

【问题讨论】:

您生成的查询不是无效的吗?您还在编写准备好的声明,对吗?如果不对其进行参数化,它并不比传入用户数据更安全(这绝不是安全的)。 警告:使用 PDO 时,您应该使用带有占位符值的 prepared statements,并将任何用户数据作为单独的参数提供。在此代码中,您可能有严重的SQL injection bugs。永远不要使用字符串插值或连接,而是使用 prepared statements 并且永远不要将 $_POST$_GET 或任何用户数据直接放在查询中。有关一般指导和建议,请参阅 PHP The Right Way。 ????:“看起来您正在编写自己的 ORM。您是否考虑过使用已经编写、测试和广泛支持的 ORM,例如 Doctrine、Propel 或 @987654327 @?” 我是 php 新手,我需要一个基于 pdo 的表单处理器,但在网上找不到它,所以尝试自己编写。 @tadman 如果您是 PHP 新手,那很好,但这也是一个很好的理由去使用已建立的东西,而不是痛苦地一点一点地构建自己的 ORM。这些事情非常复杂,充满了小问题,需要花费大量时间来理解和修复。一个完整的development framework 将为您的应用程序结构和一堆好的社区示例提供工作。 Fat-Free Framework 和 Laravel 就是两个很好的例子。 【参考方案1】:

lastInsertId() 不是PDOStatement 的方法,它只是PDO 的方法。因此,即使您使用语句来执行查询,您仍然必须在连接上调用 lastInsertId()

public function insert($postcol, $postval, $table)
    $sql="INSERT INTO ".$table;
    $sql.=" ".$postcol;
    $sql.=" VALUES ".$postval;
    $stmt = $this->conn->prepare($sql);
    $stmt->execute();
    $lastid = $this->conn->lastInsertId();
    return($lastid);

【讨论】:

以上是关于lastinsertId() 在与 exec() 一起工作时不能与 execute() 一起工作?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 PDO 的 Oracle 驱动程序不实现 lastInsertId()?

如何添加 lastInsertId()? [复制]

多线程单连接中的 PDO::lastInsertId() 是不是安全?

PDO:lastInsertId 返回啥值? [复制]

插入多行,parent = lastInsertId

雄辩的 lastInsertId