【问题标题】:How to echo a MySQLi prepared statement?如何回显 MySQLi 准备好的语句?
【发布时间】:2010-11-01 01:40:36
【问题描述】:

我目前正在使用 MySQLi,试图弄清楚它是如何工作的。在我目前的项目中,我总是喜欢在编码时回显一个查询字符串,以确保一切正确,并快速调试我的代码。但是...如何使用准备好的 MySQLi 语句来做到这一点?

例子:

$id = 1;
$baz = 'something';

if ($stmt = $mysqli->prepare("SELECT foo FROM bar WHERE id=? AND baz=?")) {
  $stmt->bind_param('is',$id,$baz);
  // how to preview this prepared query before acutally executing it?
  // $stmt->execute();
}

我一直在浏览此列表 (http://www.php.net/mysqli),但没有任何运气。


编辑

好吧,如果在 MySQLi 中无法实现,也许我会坚持这样的做法:

function preparedQuery($sql,$params) {
  for ($i=0; $i<count($params); $i++) {
    $sql = preg_replace('/\?/',$params[$i],$sql,1);
  }
  return $sql;
}

$id = 1;
$baz = 'something';

$sql = "SELECT foo FROM bar WHERE id=? AND baz=?";

echo preparedQuery($sql,array($id,$baz));

// outputs: SELECT foo FROM bar WHERE id=1 AND baz=something

显然远非完美,因为它仍然是相当多余的——这是我想阻止的——而且它也没有让我知道 MySQLi 对数据做了什么。但我想这样我可以快速查看所有数据是否存在并且在正确的位置,与手动将变量拟合到查询中相比,它会节省我一些时间 - 这可以是许多变量的痛苦。

【问题讨论】:

  • 哇,好像没有办法。好难过。。。本来希望能切换到mysqli的,但是我需要把所有运行过的SQL语句都记录下来作为一个历史记录。
  • 你可以让你的 MySQL 服务器记录它收到的所有查询
  • 是的,这很有帮助,但我不想记录 SELECTS,而且它对调试没有多大帮助,因为每秒可能有很多查询。

标签: php mysqli


【解决方案1】:

我能够使用var_dump() 至少获得有关 mysqli_stmt 的更多信息:

  $postmeta_sql = "INSERT INTO $db_new.wp_postmeta (post_id, meta_key, meta_value) VALUES (?, ?, ?)";
  $stmt = $new_conn->prepare($postmeta_sql);
  $stmt->bind_param("sss", $post_id, $meta_key, $meta_value);
  echo var_dump($stmt);
  $stmt->execute();
  $stmt->close();

【讨论】:

    【解决方案2】:

    您可以在 mysql 服务器上打开日志查询。 只需执行命令:

    sql> SHOW VARIABLES LIKE "general_log%";
    sql> SET GLOBAL general_log = 'ON';
    

    并观察日志文件中的查询。 测试后关闭注销:

    sql> SET GLOBAL general_log = 'OFF';
    

    【讨论】:

      【解决方案3】:

      我最近更新了这个项目,包括作曲家集成、单元测试和更好地处理通过引用接受参数(这需要更新到 php 5.6)。


      为了响应我在使用PDO 创建以解决相同问题而创建的项目中收到的请求,我在 github 上创建了mysqli 的扩展,似乎可以解决您的问题:

      https://github.com/noahheck/E_mysqli

      这是一组扩展本机 mysqlimysqli_stmt 类的类,通过将绑定参数插入到准备好的查询中,您可以查看要在 db 服务器上执行的查询示例,然后为您提供访问结果查询字符串作为stmt 对象的新属性:

      $mysqli  = new E_mysqli($dbHost, $dbUser, $dbPass, $dbName);
      
      $query = "UPDATE registration SET name = ?, email = ? WHERE entryId = ?";
      
      $stmt = $mysqli->prepare($query);
      
      $stmt->bindParam("ssi", $_POST['name'], $_POST['email'], $_POST['entryId']);
      
      $stmt->execute();
      
      echo $stmt->fullQuery;
      

      将导致:

      UPDATE registration SET name = 'Sue O\'reilly', email = 'sue.o@example.com' WHERE entryId = 5569
      

      请注意,考虑到数据库服务器上的字符集,对 fullQuery 中的值进行了适当的转义,这应该使此功能适用于例如日志文件、备份等。

      使用它有一些注意事项,在 github 项目的自述文件中有概述,但是,特别是对于开发、学习和测试,它应该提供一些有用的功能。

      正如我在 github 项目中所述,我没有任何使用 mysqli 扩展的实际经验,并且该项目是应其姊妹项目用户的要求创建的,因此可以提供任何反馈非常感谢在生产中使用它的开发人员。

      免责声明 - 正如我所说,我做了这个扩展。

      【讨论】:

        【解决方案4】:

        我过去一直在努力解决这个问题。所以为了解决这个问题,我编写了一个小函数来根据 SQL、标志和变量为我构建 SQL。

        //////////// Test Data //////////////
        $_GET['filmID'] = 232;
        $_GET['filmName'] = "Titanic";
        $_GET['filmPrice'] = 10.99;
        
        //////////// Helper Function //////////////
        function debug_bind_param(){
            $numargs = func_num_args();
            $numVars = $numargs - 2;
            $arg2 = func_get_arg(1);
            $flagsAr = str_split($arg2);
            $showAr = array();
            for($i=0;$i<$numargs;$i++){
                switch($flagsAr[$i]){
                case 's' :  $showAr[] = "'".func_get_arg($i+2)."'";
                break;
                case 'i' :  $showAr[] = func_get_arg($i+2);
                break;  
                case 'd' :  $showAr[] = func_get_arg($i+2);
                break;  
                case 'b' :  $showAr[] = "'".func_get_arg($i+2)."'";
                break;  
                }
            }
            $query = func_get_arg(0);
            $querysAr = str_split($query);
            $lengthQuery = count($querysAr);
            $j = 0;
            $display = "";
            for($i=0;$i<$lengthQuery;$i++){
                if($querysAr[$i] === '?'){
                    $display .= $showAr[$j];
                    $j++;   
                }else{
                    $display .= $querysAr[$i];
                }
            }
            if($j != $numVars){
                $display = "Mismatch on Variables to Placeholders (?)"; 
            }
            return $display;
        }
        
        //////////// Test and echo return //////////////
        
        echo debug_bind_param("SELECT filmName FROM movies WHERE filmID = ? AND filmName = ? AND price = ?", "isd", $_GET['filmID'], $_GET['filmName'], $_GET['filmPrice']);
        

        我还构建了一个小的在线工具来提供帮助。

        Mysqli Prepare Statement Checker

        【讨论】:

        • 检查$i
        • 缺少重要检查!即使您使用在列名中替换 qmark,您的工具和函数也会显示正确的 SQL stmt。用户应该知道列名中不允许使用参数,但这样的错误很难找到,不幸的是,这个功能在这里也不起作用..
        【解决方案5】:

        我认为你不能——至少不能以你希望的方式。您要么必须自己构建查询字符串并执行它(即不使用语句),要么寻找或创建支持该功能的包装器。我使用的是Zend_Db,我会这样做:

        $id = 5;
        $baz = 'shazam';
        $select = $db->select()->from('bar','foo')
                               ->where('id = ?', $id)
                               ->where('baz = ?', $baz); // Zend_Db_Select will properly quote stuff for you
        print_r($select->__toString()); // prints SELECT `bar`.`foo` FROM `bar` WHERE (id = 5) AND (baz = 'shazam')
        

        【讨论】:

        • 对复杂的准备好的语句的疏忽,您可能希望将其复制并粘贴到查询窗口中以进行检查/测试。字符串显然在 somewhere 中,为什么不给我们一个只读的statement 属性呢?
        【解决方案6】:

        只需将其设置为死并输出最后执行的查询。错误处理应该为您提供有意义的信息,您可以使用这些信息来修复您的查询。

        【讨论】:

          猜你喜欢
          • 2012-12-01
          • 2012-01-31
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-06-19
          • 2012-03-26
          相关资源
          最近更新 更多