mysqli准备好的语句返回0行,没有错误

时间:2019-10-05 02:57:52

标签: php mysql mysqli

我在php中创建了一系列我一直使用的辅助函数,因为它们使准备好的mysqli语句对我来说变得更快,更容易理解。他们已经在其他项目上工作了,但是由于某种原因,这个特定项目上的问题使我难以理解...它可以完全脱机工作,但是当我将其上传到服务器时,我得到了0行。我以为它一定是某个地方,但是我无法终生弄清楚它是什么。运行此命令时,Apache日志中没有错误。

在这种特殊情况下,我试图验证数据库中是否存在一系列值。如果是这样,则返回true。如果没有,则返回false。

以下是辅助功能:

function verifyRow($a_verify) {
    //Pass $mysqli connection variable
    global $mysqli;

    //Create a string from the selection criteria
    $selection = implode(", ", (array) $a_verify->selection);

    //Transfer table contents to table variable just for consistency
    $table = $a_verify->table;

    //Create a string from the parameter types
    $type = implode("", (array) $a_verify->type);

    //Push a reference to the string of types to the parameter array
    $a_params[] =& $type;

    //For each result parameter, push a column = result string into the colvals array and create a reference to the parameter in the parameters array
    foreach ($a_verify->columns as $key => $value) {
        $a_colvals[] = "{$value} = ?";
        $a_params[] =& $a_verify->results->$key;
    }

    //Create a string from the column = result array
    $colvals = implode(" AND ", $a_colvals);

    //Generate a query
    $query = "SELECT {$selection} FROM {$table} WHERE {$colvals} LIMIT 1";

    //Prepare statement and error checking
    if (!($stmt = $mysqli->prepare($query))) {
        print "Prepare failed: (" . $mysqli->errno . ") " . $mysqli->error;
    }

    //Bind parameters and error checking
    if (!(call_user_func_array(array($stmt, 'bind_param'), $a_params))) {
        print "Binding parameters failed: (" . $mysqli->errno . ") " . $mysqli->error;
    }

    //Execute statement and error checking
    if (!$stmt->execute()) {
        print "Execute failed: (" . $stmt->errno . ") " . $stmt->error;
    }

    //Get the result
    $result = $stmt->get_result();

    //Bind the result to a variable
    $row = $result->fetch_assoc();

    //If the row exists, return true
    if ($row) {
        return true;
    }
    //If the row doesn't exist, return false
    else {
        return false;
    }
}

这是我尝试检索结果的方式:

// Confirm there is a user in the db with this user code
$a_verify = (object) array(
    "selection" => (object) array(
        "*"
    ),
    "table" => "`users`",
    "columns" => (object) array(
        "`code`"
    ),
    "results" => (object) array(
        "'123456'"
    ),
    "type" => (object) array(
        "s"
    )
);
print verifyRow($a_verify); //Ideally 'true'

以下是“用户”数据库的设置方式:

|-----|---------------|--------|
| id  |     email     |  code  |
--------------------------------
| 0   | test@test.com | 123456 |
--------------------------------

任何想法可能是什么问题?这让我发疯。

1 个答案:

答案 0 :(得分:1)

助手功能很棒,在这里我完全与您同在。但是... 您称这个令人眼花skyscraper乱的代码摩天大楼比真正的香草SQL“更快捷,更容易”吗?

由于某种原因,您一直在不断将代码从一种格式转换为另一种格式。例如,您正在创建一个数组array("*"),然后将其转换为对象(object),然后...将其转换回数组(array) $a_verify->selection。为什么?

或者您进行一个简单的SQL查询SELECT * FROM users WHERE code = ?,然后创建一个多行构造,其中SQL关键字被数组键替换,并添加了许多引号,括号和其他内容。 然后将其转换回SQL

SQL是一种了不起的语言,由于其简单性和严格性,它可以生存数十年。没有理由将其拆成碎片以添加结构。 SQL已经具有结构。 它具有许多您的助手不支持的功能。最后,通过大量的努力,您将获得一个严格限制的SQL版本,该版本具有复杂的语法和复杂的实现。您称其为辅助功能吗?

最后但并非最不重要。您可以自由地在其中添加列名和表名的此类功能寻求SQL注入。您的other question会显示出令人震惊的做法-您正在直接在SQL中添加用户输入。如果您仍要进行注射,为什么还要准备好的语句呢?有关如何处理此类情况的信息,请参见this answer

让我为您展示一个真正的助手功能。它使您的代码简短易读,并且支持SQL的全部功能(例如,对结果进行排序):

function prepared_query($mysqli, $sql, $params, $types = "")
{
    $types = $types ?: str_repeat("s", count($params));
    $stmt = $mysqli->prepare($sql);
    $stmt->bind_param($types, ...$params);
    $stmt->execute();
    return $stmt;
}

如果您对它的工作方式感兴趣,可以阅读我写的here的说明。

现在,让我们根据我的方式重写您的辅助函数

function verifyRow($mysqli, $sql, $parameters) {
    $result = prepared_query($mysqli, $sql, $parameters)->get_result();
    return (bool)$result->fetch_assoc();
}

只需两行代码!

现在要验证实际的行:

var_dump(verifyRow($mysqli, "SELECT 1 FROM users WHERE code = ?", ['12345']));

一行而不是一排。

现在要问为什么它什么也找不到。有两个可能的原因。

  • 实际上存在一些配置错误。
  • 一个简单得多的情况:您正在查询的表中目前没有此类数据

要测试前者,必须启用PHP错误报告。如果您的代码无法按预期工作,那么某个地方一定有一个错误,您所需要的只是捕获它。将这两行添加到您的代码中

error_reporting(E_ALL);
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
ini_set('log_errors',1); // well to be 100% sure it will be logged

为了确保所有PHP和mysql错误都会出现。然后再次运行代码。如果不会产生任何错误,则可能是您的系统配置正确。

现在测试您的数据。编写另一个查询,该查询将返回表中的所有行

$sql = "SELECT code FROM users WHERE 1 = ?";
$result = prepared_query($mysqli, $sql, [1])->get_result();
var_dump($result->fetch_all(MYSQLI_ASSOC));

并查看您的数据库中真正拥有的内容。可能没有行或不同的代码值。提示:可能有不可打印的字符会阻止匹配。要显示它们,请使用非常方便的功能rawurlencode():它将保留所有基本字符,但将所有其他字符转换为十六进制代码,使它们很容易使用