我在寻找一种动态更改MYSQLi调用中使用的变量数量的方法。我偶然发现了5年前PHP.net上一个非常有用的帖子(http://php.net/manual/en/mysqli-stmt.bind-param.php#100879)。然而,我在事情上有点疯狂,我想知道我对他的作品的改编是否仍然安全、高效/充满了错误,我没有足够聪明地看到这些错误。
这个想法有五个方面:
我希望,所有这些都是通过这样的方式实现的:
doMYSQL(‘插入表(id,name)值($id,$name)');
注意,如果需要的话,在下面的函数中,查询(带有变量内联,就像旧的MYSQL)被单引号包围--变量被解析为实际的变量名,而不是其值。这些值只在准备MYSQLi准备语句的阶段发生一次(因此,据我所知,应该有相同的安全性来防止强制令攻击)。
现在正式的笔记。我希望任何反馈意见,如何使这更好,或如果有一个明显的错误,某处。最后一条注释("Misc代码“)下面的所有代码都来自PHP.net帖子,其中大部分我不明白,所以对它的任何评论也是有帮助的。如果这个函数确实通过了,它肯定会使我的生活变得更容易,所以希望其他人也能找到它的用途:)。
澄清一下,这在我尝试过的所有测试中都奏效了,所以我没有理由认为有什么问题。我只是有足够的经验,知道我没有足够的经验,不知道是否有危险。因此,我向你们致敬,并要求协助验证该功能的安全性。
<?php
/*
doMYSQL($sql, $debug_local [optional]);
$sql = Statement to execute;
$debug_local = 'print' to show query on page but not run, 'both' to show it and run, leave blank for normal execution.
(You can add a $debug variable at the top of the page to control all doMYSQL functions at once, though local ones take precedence.
*/
function doMYSQL($sql, $debug_local = 'none')
{
$mysqli = new mysqli("localhost", "username", "password", "database");
$print = $sql; // Save unaltered copy in case 'print' is enabled later
// Get debug settings (priority is user-set $debug_local, then global $debug, then default to 'none')
global $debug;
if (($debug == 'print' OR $debug == 'both') AND $debug_local == 'none'){$debug_local = $debug;}
// Create list of variables in the query
preg_match_all('/\$\w+/',$sql,$matches);
// For each variable found, find its value and add its kind and value to $params
$params = array();
foreach ($matches[0] AS $match)
{
$match = substr($match,1); // Get rid of the now-unneccessary '$'' on the variable name
global $$match; // Get the global value for that variable
$kind = gettype($$match); // Get the kind for that variable
// Convert PHP kind to mysqli kind for bind_result
if ($kind == "integer"){$kind = 'i';}
if ($kind == "double"){$kind = 'd';}
if ($kind == "string"){$kind = 's';}
$params[0] .= $kind; // Adds to ongoing list of types in $param[0]
$params[] = $$match; // Adds to ongoing list of values in $params[1+]
$sql = str_replace("$"."$match", '?', $sql); // Switch variable with '?' in the query
$print = str_replace("$"."$match", $$match."[$kind]", $print); // Switch variable with '?' in the query
}
// If debug is print or both, print
if ($debug_local == "print" OR $debug_local == "both")
{
echo "MYSQLi Debug: $print<br>";
}
// If debug is not 'print', run it
if ($debug_local != 'print')
{
// Get first word; if a select/explain, set $close to false; otherwise set to 'true.' If irregular query, error message.
$temp = explode(' ',trim($sql),2);
$firstword = strtolower($temp[0]);
if ($firstword == 'select' OR $firstword == 'explain'){$close=false;}
else if ($firstword == 'update' OR $firstword == 'delete' OR $firstword == 'insert'){$close=true;}
else {echo "Invalid first word on query $query!<br>";}
// Start misc code found on the PHP link
$stmt = $mysqli->prepare($sql) or die ("Failed to prepared the statement!");
call_user_func_array(array($stmt, 'bind_param'), refValues($params));
$stmt->execute();
if($close){
$result = $mysqli->affected_rows;
} else {
$meta = $stmt->result_metadata();
while ( $field = $meta->fetch_field() ) {
$parameters[] = &$row[$field->name];
}
call_user_func_array(array($stmt, 'bind_result'), refValues($parameters));
while ( $stmt->fetch() ) {
$x = array();
foreach( $row as $key => $val ) {
$x[$key] = $val;
}
$results[] = $x;
}
$result = $results;
}
$stmt->close();
$mysqli->close();
return $result;
}
}
function refValues($arr)
{
if (strnatcmp(phpversion(),'5.3') >= 0) //Reference is required for PHP 5.3+
{
$refs = array();
foreach($arr as $key => $value)
$refs[$key] = &$arr[$key];
return $refs;
}
return $arr;
}
Examples (generic):
doMYSQL('SELECT * FROM table WHERE id = $id');
doMYSQL('SELECT * FROM table');
doMYSQL('INSERT INTO table(id, name) VALUES ($id,$name)');
Examples (with data):
$user = 1;
$location = 'California';
$result = doMYSQL('SELECT * FROM watchlists_locations WHERE user = $user AND location = $location');
print_r($result);
doMYSQL('INSERT INTO watchlists_locations(user, location) VALUES ($user,"1000")');
?>发布于 2015-12-02 06:15:07
呵呵,我明白你想要什么,但不必这么复杂:)
如果您想使用mysqli,我只需使用双引号,然后像"SELECT * FROM table WHERE id = $id“那样发送您的SQL。首先通过mysqli_real_escape_string()运行来自用户输入的任何内容。
至于根据查询类型返回适当的响应,下面是我使用的函数的缩减版本。
function query($sql) {
$arr = explode(' ',trim($sql));
$command = strtolower($arr[0]);
switch ($command) {
case 'call':
case 'select':
// run query and return results
break;
case 'insert':
case 'replace':
// run query, then return insert_id
break;
case 'update':
case 'delete':
// run query and return resulting integer (rows affected)
break;
}
} 尽管如果您想安全、快速地绑定变量,我将放弃'mysqli‘并使用PDO方法。
$result = query("SELECT * FROM table WHERE id = :id", [':id' => $id]);
function query($sql, $params) {
$db = new PDO('mysql:database=yourdb;host=127.0.0.1', 'user', 'password');
$stmt = $db->prepare($sql);
$arr = explode(' ',trim($sql));
$command = strtolower($arr[0]);
switch ($command) {
case 'call':
case 'select':
// run query and return results
$stmt->execute($params);
return $stmt->fetchAll();
break;
case 'insert':
case 'replace':
// run query, then return insert_id
return $stmt->execute($params);
break;
case 'update':
case 'delete':
// run query and return resulting integer (rows affected)
return $stmt->execute($params);
break;
}
} https://stackoverflow.com/questions/34035710
复制相似问题