php – 将mySQL插入和更新语句切换到PDO预处理语句以防止SQL注入
我正在尝试将这些mySQl INSERT INTO和Update语句切换到PDO预处理语句(主要是为了防止SQL注入),但是我在使语法正确方面遇到了一些困难.
我目前正在使用两种类型的INSERT / Update语句: 声明1 – 名称是硬编码的 $qry = "INSERT INTO customer_info(fname,lname,email,user_name,password) VALUES('$_POST[fname]','$_POST[lname]','$_POST[email]','$user_name','".sha1($salt + $_POST['password'])."')"; $result = @mysql_query($qry) 声明2 – 动态添加名称 不是列出每个元素的名称,而是动态添加大多数名称(名称被引用为$fieldlist或$setlist,值为$vallist).唯一的硬编码名称/值是user_id或者是数组.我在下面列出了完整的代码. $result = mysql_query('UPDATE fit_table SET '.$setlist.' WHERE user_id='.$user_id); if (mysql_affected_rows()==0) { $result = mysql_query('INSERT INTO fit_table ('.$fieldlist.') VALUES ('.$vallist.')'); }; 这就是我尝试过的: 声明1 – 基于此帖子https://stackoverflow.com/a/60530/1056713 $stmt = $conn->prepare("INSERT INTO customer_info VALUES(:fname,:lname,:email,:user_name,:password)"); $stmt->bindValue(':fname',$fname); $stmt->bindValue(':lname',$lname); $stmt->bindValue(':email',$email); $stmt->bindValue(':user_name',$user_name); $stmt->bindValue(':password ',$password); $stmt->execute(); 声明2 – 基于此PDO包装器https://github.com/Xeoncross/DByte/blob/master/DB.php(在本文中引用https://stackoverflow.com/a/12500462/1056713) static function insert($fit_table,array $fieldlist){ $query = "INSERT INTO`$fit_table`(`" . implode('`,`',array_keys('.$fieldlist.')). '`) VALUES(' . rtrim(str_repeat('?,',count($fieldlist = array_values('.$vallist.'))),') . ')'; return DB::$p ? DB::column($query . 'RETURNING` user_id `',$fieldlist) : (DB::query($query,$fieldlist) ? static::$c->lastInsertId() : NULL); } 语句2的完整代码(这是目前动态添加名称的方式) // INSERT $fieldlist=$vallist=''; foreach ($_POST as $key => $value) { if ($key=='pants_waistband'){$value= implode(',$value);} $fieldlist.=$key.','; $vallist.='''.($value).'','; } $fieldlist=substr($fieldlist,-1); $vallist=substr($vallist,-1); $fieldlist.=',user_id'; $vallist.=','.$user_id; // UPDATE $setlist=''; foreach ($_POST as $key => $value) { if ($key=='pants_waistband'){$value= implode(',$value);} $setlist.=$key .'=''.$value.'','; } $setlist=substr($setlist,-1); $result = mysql_query('UPDATE fit_table SET '.$setlist.' WHERE user_id='.$user_id); if (mysql_affected_rows()==0) { $result = mysql_query('INSERT INTO fit_table ('.$fieldlist.') VALUES ('.$vallist.')');} 解决方法
看,白名单并不像看起来那么无聊!
动态查询很棒,没有理由放弃这个想法. 至少你可以使它成为半动态的,以避免所有这些重复. PDO有一个很棒的功能 – 它可以接受带有值的数组,不需要重复绑定. $stmt = $conn->prepare('INSERT INTO customer_info VALUES(?,?,?)'); $stmt->execute($_POST); 如果$_POST包含正确顺序的确切字段数,它将被执行. 好吧,让它既安全又动态. function pdoSet($fields,&$values,$source = array()) { $set = ''; $values = array(); if (!$source) $source = &$_POST; foreach ($fields as $field) { if (isset($source[$field])) { $set.="`$field`=:$field,"; $values[$field] = $source[$field]; } } return substr($set,-2); } 它将返回看起来像的字符串 `field1`=?,`field2`=?,`field3`=? 并将填充$values数组以供PDO查询使用. 请注意,Mysql允许INSERT和UPDATE查询的SET语法 – 不需要VALUES语法.所以,这两种功能都有. 对于插入物来说,它就像 $fields = array("fname","lname","email","user_name"); $stmt = $dbh->prepare("UPDATE users SET ".pdoSet($fields,$values)); $stmt->execute($values); 对于任何数量的领域,它都将保持相同的3线程! 对于更新,它需要更长的代码.我们需要为查询添加一些条件,以及向$values数组添加另一个成员. $fields = array("fname",$values)." WHERE id = :id"); $values["id"] = $_POST['id']; $stmt->execute($values); 唯一的问题是如何添加不在$_POST数组中的自定义字段. $_POST['password'] = sha1($_POST['email'].$_POST['password']); 希望这是你要求的. 只需澄清一件事.准备好的陈述不足以阻止注射,你的案例就是一个很好的例子.他们只处理数据,但保护字段名称是你的负担.然而,你使用的旧mysql方式没有任何问题.您的代码只缺少相同的白名单(当然还有正确的数据格式).但如果添加,它将使您的mysql查询像PDO一样安全. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |