This question already has answers here:
How can I prevent SQL injection in PHP?
(27 answers)
Closed 9 years ago.
i had a sql injection in my code, i checked it with havji.
so i was thinking of a fix, and i set the type of my values to integers or strings
like this. would this do the trick ? like no more injections ??? NOTHING TO WORRY ABOUT ?
my code IS below,
sorry for my bad english!
function get_page_by_id($page_id) {
settype($page_id, "integer");
global $connection;
$query = "SELECT * ";
$query .= "FROM pages ";
$query .= "WHERE id=" . $page_id ." ";
$query .= "LIMIT 1";
$result_set = mysql_query($query, $connection);
confirm_query($result_set);
// REMEMBER:
// if no rows are returned, fetch_array will return false
if ($page = mysql_fetch_array($result_set)) {
return $page;
} else {
return NULL;
}
}
CODE BEFORE FIX
function get_page_by_id($page_id) {
global $connection;
$query = "SELECT * ";
$query .= "FROM pages ";
$query .= "WHERE id=" . $page_id ." ";
$query .= "LIMIT 1";
$result_set = mysql_query($query, $connection);
confirm_query($result_set);
// REMEMBER:
// if no rows are returned, fetch_array will return false
if ($page = mysql_fetch_array($result_set)) {
return $page;
} else {
return NULL;
}
}
What you normally want to do is use a prepared statement instead. For php you can read about one option here.
Here is the example from that page
<?php
$stmt = $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (:name, :value)");
$stmt->bindParam(':name', $name);
$stmt->bindParam(':value', $value);
// insert one row
$name = 'one';
$value = 1;
$stmt->execute();
// insert another row with different values
$name = 'two';
$value = 2;
$stmt->execute();
?>
Try the following code:
$page_id = mysql_real_escape_string(stripslashes($page_id));
Related
This question already has an answer here:
Writing a PDO search query from a PHP array
(1 answer)
Closed 2 years ago.
I am playing with the PDO option of PHP, and I am finding it strange it does not work. I think it is because of the binding of parameters, but I am not sure. Can anyone help me please.
if(isset($_POST['submit']))
{
$query = "SELECT * FROM occasions WHERE naam IS NOT NULL";
$stmt = $pdo->prepare($query);
if (isset($_POST['merk'])) {
$query .= " AND merk = :merk";
$merk = $_POST['merk'];
$stmt->bindParam(':merk', $merk);
}
if($stmt->execute())
{
echo "query is executed";
print_r($query);
}
else
{
echo "query is niet executed";
}
while($result = $stmt->fetch())
{
echo "<br>";
echo $result['naam'];
}
}
Here is a better way to frame your code. Try this. I believe this will work.
$merk = (!empty($_POST['merk']))?$_POST['merk']:null;
$brandstof = (!empty($_POST['brandstof']))?$_POST['brandstof']:null;
if(isset($_POST['submit'])){
$query = "SELECT * FROM occassions WHERE naam IS NOT NULL";
if($merk != null){
$query .= " AND merk = :merk";
}
if($brandstof != null){
$query .= " AND brandstof = :brandstof";
}
$stmt = $pdo->prepare($query);
if($merk != null){
$stmt-> bindValue(':merk', $merk);
}
if($brandstoff != null){
$stmt-> bindValue(':brandstof', $brandstof);
}
$stmt-> execute();
while($result = $stmt->fetch()){
echo "<br>";
echo $result['naam'];
}
}
Trying to get a function working to create simple CRUD "Select" with multiple parameters to any table. I think I got the hardest part, but couldn't fetch the data right now. Maybe I'm doing something wrong I can't figure out.
My prepared statement function:
function prepared_query($mysqli, $sql, $params, $types = ""){
$types = $types ?: str_repeat("s", count($params));
if($stmt = $mysqli->prepare($sql)) {
$stmt->bind_param($types, ...$params);
$stmt->execute();
return $stmt;
} else {
$error = $mysqli->errno . ' ' . $mysqli->error;
error_log($error);
}
}
The query creator:
function create_select_query($table, $condition = "", $sort = "", $order = " ASC ", $clause = ""){
$table = escape_mysql_identifier($table);
$query = "SELECT * FROM ".$table;
if(!empty($condition)){
$query .= create_select_query_where($condition,$clause);
}
if(!empty($sort)){
$query .= " ORDER BY ".$sort." $order";
}
return $query;
}
The helper function to create the WHERE clause:
function create_select_query_where($condition,$clause){
$query = " WHERE ";
if(is_array($condition)){
$pair = array();
$size = count($condition);
$i = 0;
if($size > 1){
foreach($condition as $field => $val){
$i++;
if($size-1 == $i){
$query .= $val." = ? ".$clause. " ";
}else{
$query .= $val." = ? ";
}
}
}else{
foreach($condition as $field => $val){
$query .= $val." = ? ";
}
}
}else if(is_string($condition)){
$query .= $condition;
}else{
$query = "";
}
return $query;
}
The select function itself:
function crud_select($conn, $table, $args, $sort, $order, $clause){
$sql = create_select_query($table, array_keys($args),$sort, $order, $clause);
print_r($sql);
if($stmt = prepared_query($conn, $sql, array_values($args))){
return $stmt;
}else{
$errors [] = "Something weird happened...";
}
}
When I create the query, it seems to be OK but can't fetch the data. If I create an array with only one argument the query translates into:
SELECT * FROM `teste_table` WHERE id = ?
If I create with multiple parameters, it turns like this:
SELECT * FROM `teste_table` WHERE id = ? AND username = ?
So, how can I properly fetch the data from the select. This should be used for multiple purposes, so I could get more than one result, so the best way would be fetch data as array I guess.
I guess I'm close, but can't figure it out. Thanks
I told you to limit your select function to a simple primary key lookup. And now you opened a can of worms. As a result you are getting entangled implementation code and unreadable application code.
$table, $args, $sort, $order, $clause
What all these variables are for? How you're going to call this function - a list of gibberish SQL stubs in a random order instead of plain and simple SQL string? And how to designate a list of columns to select? How to use JOINS? SQL functions? Aliases? Why can't you just write a single SQL statement right away? You already have a function for selects, though without this barbaric error reporting code you added to it:
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;
}
Just stick to it and it will serve you all right.
$sql = "SELECT * FROM `teste_table` WHERE id = ? AND username = ?";
$stmt = prepared_query($mysqli, $sql, [$id, $name]);
$row = $stmt->get_result()->fetch_assoc();
The only specific select function could be, again, a simple primary key lookup:
function crud_find($conn, $table, $id)
{
$table = escape_mysql_identifier($table);
$sql = "SELECT * FROM $table WHERE id=?";
$stmt = prepared_query($conn, $sql, [$id], "i");
return $stmt->get_result()->fetch_assoc();
}
And for the everything else just use a generic function with native SQL.
I have this in my functions.php file
function getUserOrders($userId){
global $conn;
$query = "SELECT * ";
$query .= "FROM orders ";
$query .= "WHERE userid=" . $userId . " ";
$odrset = mysqli_query($conn, $query);
while ($odr = mysqli_fetch_assoc($odrset)){
return $odr;
}
}
What I neeed to do in my orders.php file is display specific fields and their values from the returned $odr array as this snippet suggests
$userId = sql_prep($_SESSION['userid']) ;
getUserOrders($userId);
echo $odr['title'].$odr['orderid'].'<br>'
I am only able to do it in the functions.php file...
function getUserOrders($userId){
global $conn;
$query = "SELECT * ";
$query .= "FROM orders ";
$query .= "WHERE userid=" . $userId . " ";
$odrset = mysqli_query($conn, $query);
confirm_query($odrset);
while ($odr = mysqli_fetch_assoc($odrset)){
echo $odr['title'].$odr['orderid'].'<br>';
}
}
..and calling it in my orders.php file like so:
$userId = sql_prep($_SESSION['userid']) ;
getUserOrders();
which is not good since i need to recycle the function somewhere else and display different fields and their values. So I need to have $odr returned as an array in my order.php
Store it as an array and then return the array.
function getUserOrders($userId){
global $conn;
$query =
"SELECT *
FROM orders
WHERE userid= ?";
$odrset = mysqli_prepare($conn, $query);
mysqli_stmt_bind_param($odrset, 'i', $userId);
mysqli_stmt_execute($odrset);
while ($odr = mysqli_fetch_assoc($odrset)){
$return[] = $odr;
}
return $return;
}
I've updated your mysqli connection to use a parameterized query with prepared statement. You can read more about these here, http://php.net/manual/en/mysqli.quickstart.prepared-statements.php. This is the preferred approach than escaping.
Later usage...
$orders = getUserOrders($_SESSION['userid']);
foreach($orders as $order) {
echo $order['title'] . $order['orderid'];
}
You may not need the sql_prep function with this approach, I'm not sure what that did. Your questions code didn't pass the userid to the function so I don't think that was your exact usage.
mysqli_fetch_assoc only returns one record at a time so you need to store the results inside an array and return the array from the function:
// functions.php
function getUserOrders($userId){
global $conn;
$query = "SELECT * ";
$query .= "FROM orders ";
$query .= "WHERE userid=" . $userId . " ";
$odrset = mysqli_query($conn, $query);
$results = array();
while ($odr = mysqli_fetch_assoc($odrset)){
$results[] = $odr;
}
return $results;
}
// in your orders file
$userid = sql_prep($_SESSION['userid']);
$orders = getUserOrders($userid);
foreach ($order as $orders) {
echo $order['title']. $order['orderid'] . '<br>';
}
I'm new to PDO and am currently trying to rewrite all of my queries. One query that I'm having trouble rewriting is this one because it's written inside of a loop:
$search = $_GET['search'];
$code = explode(" ", $search);
$code_count = count($code);
$query = "SELECT * FROM table";
if($search != "")
{
if($code_count == 1)
{
$query .= " WHERE team LIKE '%".mysql_real_escape_string($search)."%'";
} elseif($code_count > 1)
{
for($j=0;$j<$code_count;$j++)
{
if($j != 0)
{
$query .= " OR ";
} else
{
$query .= " WHERE team LIKE '%".mysql_real_escape_string($code[$j])."%' OR ";
}
$query .= " team LIKE '%".mysql_real_escape_string($code[$j])."%'";
}
$query .= "ORDER BY team ASC";
}
} else
{
$query = "SELECT * FROM table ORDER BY team ASC";
}
$result = mysql_query($query)or die(mysql_error());
With PDO, I have tried the following.
$query = "SELECT * FROM table";
if($search != "")
{
if($code_count == 1)
{
$query .= " WHERE team LIKE ?";
$stmt = $db->prepare($query);
$stmt->bindValue(1, "%$search%", PDO::PARAM_STR);
$stmt->execute();
} elseif($code_count > 1)
{
for($j=0;$j<$code_count;$j++)
{
if($j != 0)
{
$query .= " OR ";
} else
{
$query .= " WHERE team LIKE ? OR ";
}
$query .= " team LIKE ?";
$stmt = $db->prepare($query);
$stmt->bindValue(1, "%$code[$j]%", PDO::PARAM_STR);
$stmt->execute();
}
$query .= "ORDER BY team ASC";
}
} else
{
$query = "SELECT * FROM table ORDER BY team ASC";
}
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
Not much luck with this method. I keep getting an error message reading: "nvalid parameter number: number of bound variables does not match number of tokens"
Any ideas?
Thanks,
Lance
The bind parameters are named 1 to n when you don't assign a name yourself. You need to change this line:
$stmt->bindValue(1, "%$code[$j]%", PDO::PARAM_STR);
To this:
$stmt->bindValue($j + 1, "%" . $code[$j] . "%", PDO::PARAM_STR);
Since one can pass an array of parameters to PDOStatement::execute() instead of binding each manually, one can hugely simplify the whole thing:
$code = explode(' ', $_GET['search']);
$stmt = $db->prepare('
SELECT *
FROM table
WHERE FALSE ' . str_repeat(' OR team LIKE ?', count($code)) . '
ORDER BY team ASC
');
$stmt->execute($code);
You have several errors in your rewrite:
you are calling prepare / bind / execute several times during the construction of the query. You should call prepare just once, after your query string is fully constructed, and bind+execute after the query construction.
in every iteration of your loop, you add one or two ( if j == 0) parameter to your query, but you try to bind just one per loop - so the numbers won't add up.
Generally, to use parametric queries, you need to follow the following structure:
build your query string
prepare your query string
every time you want to run your query:
bind parameters
execute
fetch
So your code should be like:
// building query
if($search != "")
{
$query = 'SELECT * FROM table ';
if($code_count == 1)
{
// note: this if is unneccessary, the loop below would generate a good SQL even for code_count 0 or 1
$query .= "WHERE team LIKE ?";
} elseif($code_count > 1)
{
for($j=0;$j<$code_count;$j++)
{
if($j != 0)
{
$query .= " OR ";
} else
{
$query .= " WHERE ";
}
$query .= " team LIKE ? ";
}
$query .= "ORDER BY team ASC";
}
} else
{
$query = "SELECT * FROM table ORDER BY team ASC";
}
// preparing
$stmt = $db->prepare($query);
// binding parameters
if($search != '' && $code_count >= 1) {
for($j=0;$j<$code_count;$j++){
$stmt->bindValue($j+1, "%".$code[$j]."%", PDO::PARAM_STR);
}
}
// execute
$stmt->execute();
// fetch
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
I have a similar problem with delete command too..
function deleteUsers($userID) {
foreach($userID as $key => $val)
{
$query = "DELETE FROM members WHERE member_id = '$val'";
$result = mysql_query($query);
}
//$query = "DELETE FROM members WHERE member_id = $userID";
//$result = mysql_query($query);
if($result)
{
return 'yes';
}
}
its not performing multi delete.... the $userID contains array. Its not going inside the Query.
When using multiple IDs use variable IN (1,2,3) format rather than simple equality. Also if you have more than one ID maybe the variable should be called $userIDs?
if(count($userID) > 0) {
$query = 'DELETE FROM members WHERE member_id IN ('. implode(',', $userID) .')';
}
Without foreach:
function deleteUsers($userID) {
if (count($userID)) {
$query = "DELETE FROM `members` WHERE `member_id` IN (".implode(",", array_values($userID)).");";
if (mysql_query($query)) { return true; }
}
return false;
}
This will make the function to understand array as well as single integer:
function deleteUsers($u) {
$condition = is_array($u)
? "member_id IN (" . implode(',', $u) . ")"
: "member_id = " . (int)$u;
$res = mysql_query("DELETE FROM `members` WHERE $condition");
return $res ? true : false;
}
Remember that your parameters are not properly escaped and cannot be trusted. To learn more on escaping SQL and preventing injection attacks read about Prepared Statements.
Please, for the love of the internet, don't built an SQL query yourself. Use PDO.