我在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 |
--------------------------------
任何想法可能是什么问题?这让我发疯。
答案 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()
:它将保留所有基本字符,但将所有其他字符转换为十六进制代码,使它们很容易使用