首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在php中创建安全的mysql准备语句?

问如何在php中创建安全的mysql准备语句?
EN

Stack Overflow用户
提问于 2009-08-17 23:06:42
回答 6查看 57.6K关注 0票数 28

我对用php在mysql中使用准备好的语句很陌生。我需要一些帮助来创建一个准备好的语句来检索列。

我需要从不同的专栏中得到信息。目前,对于测试文件,我使用完全不安全的 SQL语句:

代码语言:javascript
复制
$qry = "SELECT * FROM mytable where userid='{$_GET['userid']}' AND category='{$_GET['category']}'ORDER BY id DESC"
$result = mysql_query($qry) or die(mysql_error()); 

有人能帮我创建一个安全 mysql语句,它使用来自url参数的输入(如上面所示)吗?

额外好处:准备好的语句也会提高速度。如果我只在一页上使用准备好的报表三、四次,它会提高总体速度吗?

EN

回答 6

Stack Overflow用户

回答已采纳

发布于 2009-08-17 23:13:40

下面是一个使用mysqli的示例(对象语法--如果您愿意的话,可以很容易地转换为函数语法):

代码语言:javascript
复制
$db = new mysqli("host","user","pw","database");
$stmt = $db->prepare("SELECT * FROM mytable where userid=? AND category=? ORDER BY id DESC");
$stmt->bind_param('ii', intval($_GET['userid']), intval($_GET['category']));
$stmt->execute();

$stmt->store_result();
$stmt->bind_result($column1, $column2, $column3);

while($stmt->fetch())
{
    echo "col1=$column1, col2=$column2, col3=$column3 \n";
}

$stmt->close();

此外,如果您希望找到一种简单的方法来获取关联数组(用于SELECT *),而不必指定要绑定到哪些变量,那么这里有一个方便的函数:

代码语言:javascript
复制
function stmt_bind_assoc (&$stmt, &$out) {
    $data = mysqli_stmt_result_metadata($stmt);
    $fields = array();
    $out = array();

    $fields[0] = $stmt;
    $count = 1;

    while($field = mysqli_fetch_field($data)) {
        $fields[$count] = &$out[$field->name];
        $count++;
    }
    call_user_func_array(mysqli_stmt_bind_result, $fields);
}

要使用它,只需调用它而不是调用bind_result:

代码语言:javascript
复制
$stmt->store_result();

$resultrow = array();
stmt_bind_assoc($stmt, $resultrow);

while($stmt->fetch())
{
    print_r($resultrow);
}
票数 46
EN

Stack Overflow用户

发布于 2009-08-17 23:11:21

您可以这样写:

代码语言:javascript
复制
$qry = "SELECT * FROM mytable where userid='";
$qry.= mysql_real_escape_string($_GET['userid'])."' AND category='";
$qry.= mysql_real_escape_string($_GET['category'])."' ORDER BY id DESC";

但是要使用准备好的语句,最好使用泛型库,比如PDO

代码语言:javascript
复制
<?php
/* Execute a prepared statement by passing an array of values */
$sth = $dbh->prepare('SELECT * FROM mytable where userid=? and category=? 
                      order by id DESC');
$sth->execute(array($_GET['userid'],$_GET['category']));
//Consider a while and $sth->fetch() to fetch rows one by one
$allRows = $sth->fetchAll(); 
?>

或者,使用米斯里

代码语言:javascript
复制
<?php
$link = mysqli_connect("localhost", "my_user", "my_password", "world");

/* check connection */
if (mysqli_connect_errno()) {
    printf("Connect failed: %s\n", mysqli_connect_error());
    exit();
}

$category = $_GET['category'];
$userid = $_GET['userid'];

/* create a prepared statement */
if ($stmt = mysqli_prepare($link, 'SELECT col1, col2 FROM mytable where 
                      userid=? and category=? order by id DESC')) {
    /* bind parameters for markers */
    /* Assumes userid is integer and category is string */
    mysqli_stmt_bind_param($stmt, "is", $userid, $category);  
    /* execute query */
    mysqli_stmt_execute($stmt);
    /* bind result variables */
    mysqli_stmt_bind_result($stmt, $col1, $col2);
    /* fetch value */
    mysqli_stmt_fetch($stmt);
    /* Alternative, use a while:
    while (mysqli_stmt_fetch($stmt)) {
        // use $col1 and $col2 
    }
    */
    /* use $col1 and $col2 */
    echo "COL1: $col1 COL2: $col2\n";
    /* close statement */
    mysqli_stmt_close($stmt);
}

/* close connection */
mysqli_close($link);
?>
票数 11
EN

Stack Overflow用户

发布于 2009-08-17 23:54:31

我同意其他几个答案:

  • PHP的ext/mysql不支持参数化的SQL语句。
  • 在防范SQL注入问题时,查询参数被认为是更可靠的。
  • 如果您正确地使用mysql_real_escape_string(),它也可能是有效的,但是它的代码更冗长。
  • 在某些版本中,国际字符集存在字符不能正确转义的情况,从而留下微妙的漏洞。使用查询参数可以避免这些情况。

您还应该注意,即使使用查询参数,仍然必须对SQL注入保持谨慎,因为参数仅取代SQL查询中的文字值。如果动态构建SQL查询,并将PHP变量用于表名、列名或SQL语法的任何其他部分,则在这种情况下,查询参数或mysql_real_escape_string()帮助都不会出现。例如:

代码语言:javascript
复制
$query = "SELECT * FROM $the_table ORDER BY $some_column"; 

关于业绩:

  • 当您使用不同的参数值多次执行准备好的查询时,性能就会有好处。您避免了解析和准备查询的开销。但是,您需要在同一个PHP请求中多次执行相同的SQL查询吗?
  • 即使您可以利用这一性能优势,与您为解决性能问题所能做的许多其他事情相比,它通常也只是轻微的改进,比如有效地使用操作码缓存或数据缓存。
  • 甚至有些情况下,准备好的查询会损害性能。例如,在以下情况下,优化器不能假设它可以使用索引进行搜索,因为它必须假定参数值可能以通配符开头: 从mytable中选择* textfield喜欢哪里?
票数 8
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/1290975

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档