in my php-script i am executing on a sql-server. Everything works fine, but: I dont only have variable values, but also variable field-names. Therefore I would like to pass the field-names as a parameter for security-reasons.
the sql would be
$sql = "UPDATE STA_Kunden
SET ? = ?
WHERE (KUN_KundeNo = ?)";
$params = array($field, $value, $select);
But the field-name can not be a parameter. Therefore if someone would mess around with the field-name a sql-injection would be possible.
How can I set this secure?
Thanks
Max
You have to whitelist the values of $field and concatenate it into the query:
if (in_array($field, array('allowed_field_1', 'allowed_field_2'))) {
$sql = "UPDATE STA_Kunden SET " . $field . " = ? WHERE (KUN_KundeNo = ?)";
$params = array($value, $select);
}
Related
I've created an UPDATE statement that updates only if the string's length is greater than 0.
I'm trying to escape quotes within my UPDATE statement once the condition is met. I've been using addslashes($name), but with this new condition addslashes no longer works.
Previous:
$mysqli->query("UPDATE table SET name='".addslashes($name)."' WHERE id=1") or die($mysqli->error);
Current:
$mysqli->query("UPDATE table SET name=IF(LENGTH($name)=0, name, '$name') WHERE id=1") or die($mysqli->error);
Where do I place addslashes() for this function to correctly escape characters? Will this function even work within this particular MySQL statement for PHP?
The problem with your second query is that $name inside the call to LENGTH needs to be in quotes too i.e.
$mysqli->query("UPDATE table SET name=IF(LENGTH('$name')=0, name, '$name') WHERE id=1") or die($mysqli->error);
To use addslashes in that query, you would write:
$mysqli->query("UPDATE table SET name=IF(LENGTH('".addslashes($name)."')=0, name, '".addslashes($name)."') WHERE id=1") or die($mysqli->error);
But really you should consider using a prepared statement instead; then you won't have to worry about escaping quotes. Additionally, you should check the length of $name in PHP and not run the query at all if it is empty. Something like this should work (I'm assuming you have a variable called $id which stores the id value for the update).
if (strlen($name)) {
$stmt = $mysqli->prepare("UPDATE table SET name=? WHERE id=?");
$stmt->bind_param('si', $name, $id);
$stmt->execute() or die($stmt->error);
}
If you have multiple pieces of data to update, you could try something like this:
$name = 'fred';
$city = '';
$state = 'SA';
$id = 4;
$params = array();
foreach (array('name','city','state') as $param) {
if (strlen($$param)) $params[$param] = $$param;
}
$sql = "UPDATE table SET " . implode(' = ?, ', array_keys($params)) . " = ? WHERE id = ?";
$types = str_repeat('s', count($params)) . 'i';
$params['id'] = $id;
$stmt = $mysqli->prepare($sql);
$stmt->bind_param($types, ...$params);
$stmt->execute() or die($stmt->error);
please help me out and sorry for my bad English,
I have fetch data , on basis of that data I want to update the rows,
Follows my code
I fetched data to connect API parameters
<?php
$stmt = $db->stmt_init();
/* publish store for icube*/
$stmt->prepare( "SELECT id,offer_id,name,net_provider,date,visible,apikey,networkid FROM " ."affilate_offer_findall_icube WHERE visible='1' ");
$stmt->execute();
mysqli_stmt_execute($stmt); // <--------- currently missing!!!
mysqli_stmt_store_result($stmt);
$rows = mysqli_stmt_num_rows($stmt);
$stmt->bind_result( $id, $offer_id, $name, $net_provider, $date, $visible,$apikey,$networkid);
$sql = array();
if($rows>0)
{
while($info = $stmt->fetch() ) {
$jsondataicube = file_get_contents('filename/json?NetworkId='.$networkid.'&Target=Affiliate_Offer&Method=getThumbnail&api_key='.$apikey.'&ids%5B%5D='.$offer_id.'');
$dataicube = json_decode($jsondataicube, true);
foreach($dataicube['response']['data'][0]['Thumbnail'] as $key=>$val)
{
$offer_id = $dataicube['response']['data'][0]['Thumbnail']["$key"]['offer_id'];
$display = $dataicube['response']['data'][0]['Thumbnail']["$key"]['display'];
$filename = $dataicube['response']['data'][0]['Thumbnail']["$key"]['filename'];
$url = $dataicube['response']['data'][0]['Thumbnail']["$key"]['url'];
$thumbnail = $dataicube['response']['data'][0]['Thumbnail']["$key"]['thumbnail'];
$_filename = mysqli_real_escape_string($db,$filename);
$_url = mysqli_real_escape_string($db,$url);
$_thumbnail = mysqli_real_escape_string($db,$thumbnail);
$sql[] = '("'.$offer_id.'","icube","'.$_thumbnail.'","'.$_url.'")';
}
}
As I store values which have to be inserted in 'sql'
now
$stmt->prepare( "SELECT offer_id FROM " ."affilate_offer_getthumbnail_icube ORDER BY 'offer_id' ASC");
$stmt->execute();
mysqli_stmt_execute($stmt); // <--------- currently missing!!!
mysqli_stmt_store_result($stmt);
$rows = mysqli_stmt_num_rows($stmt);
$stmt->bind_result($offer_id);
$sqlimplode = implode(',', $sql);
if($rows>0)
{
$query = "UPDATE affilate_offer_getthumbnail_icube WHERE offer_id='".$offer_id."' SET '".$sqlimplode."'";
$stmt->prepare( $query);
$execute = $stmt->execute();
}
else
{
$query= "INSERT INTO affilate_offer_getthumbnail_icube(offer_id, net_provider,logo2020,logo100) VALUES".$sqlimplode;
$stmt->prepare( $query);
$execute = $stmt->execute();
}`
`
Insert query working well,but how can I update all the data like insert query ?
My Answer is refering to a "set and forget"-strategy. I dont want to look for an existing row first - probably using PHP. I just want to create the right SQL-Command and send it.
There are several ways to update data which already had been entered (or are missing). First you should alter your table to set a problem-specific UNIQUE-Key. This is setting up a little more intelligence for your table to check on already inserted data by its own. The following change would mean there can be no second row with the same value twice in this UNIQUE-set column.
If that would occur, you would get some error or special behaviour.
Instead of using PHPMyAdmin you can use this command to set a column unique:
ALTER TABLE `TestTable` ADD UNIQUE(`tablecolumn`);
After setting up your table with this additional intelligence, you alter your Insert-Command a little bit:
Instead of Insert you can drop and overwrite your Datarow with
REPLACE:
$query= "REPLACE INTO affilate_offer_getthumbnail_icube
(offer_id, net_provider,logo2020,logo100) VALUES (".$sqlimplode.")";
See: Replace Into Query Syntax
Secondly you can do this with the "On Duplicate Key"-Commando.
https://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html
$query= "INSERT INTO affilate_offer_getthumbnail_icube
(offer_id, net_provider,logo2020,logo100)
VALUES (".$sqlimplode.")
ON DUPLICATE KEY UPDATE net_provider = ".$newnetprovider.",
logo2020 = ".$newlogo2020.",
logo100 = ".$newlogo100.";";
Note: I think you missed some ( and ) around your $sqlimplode. I always put them around your implode. Maybe you are missing ' ' around strings as well.
Syntax of UPDATE query is
UPDATE table SET field1 = value1, field2 = value2 ...
So, you cannot pass your imploded array $sql to UPDATE query. You have to generate another sql-string for UPDATE query.
This is clearly incorrect:
$query = "UPDATE affilate_offer_getthumbnail_icube
WHERE offer_id='".$offer_id."' SET '".$sqlimplode."'";
If the intention is to INSERT offer_id='".$offer_id."' and then UPDATE ... SET offer_id = '".$sqlimplode."'";
You have to use two separate queries, one for INSERT and then another one for UPDATE
An Example:
$query = "INSERT INTO affilate_offer_getthumbnail_icube
(col_name) VALUES('".$col_Value."')";
//(execute it first);
$query2 = "UPDATE affilate_offer_getthumbnail_icube SET
col_name= '".$col_Value."'" WHERE if_any_col = 'if_any_Value';
//(execute this next);
Try this:
$sqlimplode = implode(',', $sql);
if($rows>0)
{
/*$fields_values = explode(',',trim(array_shift($sql), "()"));
$combined_arr = array_combine(['offer_id','net_provider','logo2020','logo100'],$fields_values);
$sqlimplode = implode(', ', array_map(function ($v, $k) { return $k . '=' . $v; }, $combined_arr, array_keys($combined_arr))); */
$query = "INSERT INTO affilate_offer_getthumbnail_icube(offer_id, net_provider,logo2020,logo100) VALUES".$sqlimplode." ON duplicate key update net_provider = values(net_provider),logo2020 = values(logo2020),logo100 = values(logo100)";
$stmt->prepare( $query);
$execute = $stmt->execute();
}
else
{
$sqlimplode = implode(',', $sql);
$query= "INSERT INTO affilate_offer_getthumbnail_icube(offer_id, net_provider,logo2020,logo100) VALUES".$sqlimplode;
$stmt->prepare( $query);
$execute = $stmt->execute();
}
I am trying to check associative array value if it is numeric, here is my code
$data = array('fullname'=>'Salah Saed', 'age'=>'33', 'gender'=>'Female');
public function insert($data, $table){
/*$query = "INSERT INTO `oop_crud`.`customers` (";
$query .= "`fullname` , `age` , `gender` )";
$query .= "VALUES ('".$fullname."', '".$age."', '".$gender."')";
*/
$feilds = array();
$feilds_value = array();
foreach ($data as $field => $field_value){
$feilds[] = $field;
echo $field;
if (is_numeric($field_value)){
$feilds_value[] = $field_value;
}else{
$feilds_value[] = "'".$field_value."'";
}
}
$query = "INSERT INTO ".$table." (";
$query .= implode(',', $feilds).")";
$query .= "VALUES (";
$query .= implode(',',$feilds_value).")";
echo $query;
It returns string, so what is wrong with my code,
in the condition section i used $field_value and this variable has array data, sow how to get array value.
First of all, MySQL inserts are type-independent, so
SET UserAge = '33'
is the same as
SET UserAge = 33
so you would be safer to just add quotes. That said, you're safest if you search for prepared statements using PDO (aka parametrized queries). Take a look at that
http://php.net/is_numeric is supposed to recognize values like 0x539 and 0b10100111001 which may not be recognized by MySQL; you would need to check these cases.
Here is simplified version of your function, in case you want to improve your query generator function,
function insert($data, $table){
$column_sql = '`' . implode('`,`', array_keys($data)) . '`';
$record_sql = "'" . implode("','", $data) . "'";
return "INSERT INTO `{$table}` ({$column_sql}) VALUES ({$record_sql})";
}
Feeding it $data and test will give
INSERT INTO `test` (`fullname`,`age`,`gender`) VALUES ('Salah Saed','33','Female')
NOTE: Need to escape values mysqli_real_escape_string(), i'll leave that upto you, as an exercise :)
Not sure how I can do this. Basically I have variables that are populated with a combobox and then passed on to form the filters for a MQSQL query via the where clause. What I need to do is allow the combo box to be left empty by the user and then have that variable ignored in the where clause. Is this possible?
i.e., from this code. Assume that the combobox that populates $value1 is left empty, is there any way to have this ignored and only the 2nd filter applied.
$query = "SELECT * FROM moth_sightings WHERE user_id = '$username' AND location = '$value1' AND english_name = $value2 ";
$result = mysql_query($query) or die(mysql_error());
$r = mysql_numrows($result);
Thanks for any help.
C
Use
$where = "WHERE user_id = '$username'";
if(!empty($value1)){
$where .= "and location = '$value1'";
}
if(!empty($value2 )){
$where .= "and english_name= '$value2 '";
}
$query = "SELECT * FROM moth_sightings $where";
$result = mysql_query($query) or die(mysql_error());
$r = mysql_numrows($result);
Several other answers mention the risk of SQL injection, and a couple explicitly mention using prepared statements, but none of them explicitly show how you might do that, which might be a big ask for a beginner.
My current preferred method of solving this problem uses a MySQL "IF" statement to check whether the parameter in question is null/empty/0 (depending on type). If it is empty, then it compares the field value against itself ( WHERE field1=field1 always returns true). If the parameter is not empty/null/zero, the field value is compared against the parameter.
So here's an example using MySQLi prepared statements (assuming $mysqli is an already-instantiated mysqli object):
$sql = "SELECT *
FROM moth_sightings
WHERE user_id = ?
AND location = IF(? = '', location, ?)
AND english_name = ?";
$stmt = $mysqli->prepare($sql);
$stmt->bind_param('ssss', $username, $value1, $value1, $value2);
$stmt->execute();
(I'm assuming that $value2 is a string based on the field name, despite the lack of quotes in OP's example SQL.)
There is no way in MySQLi to bind the same parameter to multiple placeholders within the statement, so we have to explicitly bind $value1 twice. The advantage that MySQLi has in this case is the explicit typing of the parameter - if we pass in $value1 as a string, we know that we need to compare it against the empty string ''. If $value1 were an integer value, we could explicitly declare that like so:
$stmt->bind_param('siis', $username, $value1, $value1, $value2);
and compare it against 0 instead.
Here is a PDO example using named parameters, because I think they result in much more readable code with less counting:
$sql = "SELECT *
FROM moth_sightings
WHERE user_id = :user_id
AND location = IF(:location_id = '', location, :location_id)
AND english_name = :name";
$stmt = $pdo->prepare($sql);
$params = [
':user_id' => $username,
':location_id' => $value1,
':name' => $value2
];
$stmt->execute($params);
Note that with PDO named parameters, we can refer to :location_id multiple times in the query while only having to bind it once.
if ( isset($value1) )
$query = "SELECT * FROM moth_sightings WHERE user_id = '$username' AND location = '$value1' AND english_name = $value2 ";
else
$query = "SELECT * FROM moth_sightings WHERE user_id = '$username' AND english_name = $value2 ";
But, you can also make a function to return the query based on the inputs you have.
And also don't forget to escape your $values before generating the query.
1.) don't use the simply mysql php extension, use either the advanced mysqli extension or the much safer PDO / MDB2 wrappers.
2.) don't specify the full statement like that (apart from that you dont even encode and escape the values given...). Instead use something like this:
sprintf("SELECT * FROM moth_sightings WHERE 1=1 AND %s", ...);
Then fill that raw query using an array holding all values you actually get from your form:
$clause=array(
'user_id="'.$username.'"',
'location="'.$value1.'"',
'english_name="'.$value2.'"'
);
You can manipulate this array in any way, for example testing for empty values or whatever. Now just implode the array to complete the raw question from above:
sprintf("SELECT * FROM moth_sightings WHERE 1=1 AND %s",
implode(' AND ', $clause) );
Big advantage: even if the clause array is completely empty the query syntax is valid.
First, please read about SQL Injections.
Second, $r = mysql_numrows($result) should be $r = mysql_num_rows($result);
You can use IF in MySQL, something like this:
SELECT * FROM moth_sightings WHERE user_id = '$username' AND IF('$value1'!='',location = '$value1',1) AND IF('$value2'!='',english_name = '$value2',1); -- BUT PLEASE READ ABOUT SQL Injections. Your code is not safe.
Sure,
$sql = "";
if(!empty($value1))
$sql = "AND location = '{$value1}' ";
if(!empty($value2))
$sql .= "AND english_name = '{$value2}'";
$query = "SELECT * FROM moth_sightings WHERE user_id = '$username' {$sql} ";
$result = mysql_query($query) or die(mysql_error());
$r = mysql_numrows($result);
Be aware of sql injection and deprecation of mysql_*, use mysqli or PDO instead
I thought of two other ways to solve this:
SELECT * FROM moth_sightings
WHERE
user_id = '$username'
AND location = '%$value1%'
AND english_name = $value2 ";
This will return results only for this user_id, where the location field contains $value1. If $value1 is empty, this will still return all rows for this user_id, blank or not.
OR
SELECT * FROM moth_sightings
WHERE
user_id = '$username'
AND (location = '$value1' OR location IS NULL OR location = '')
AND english_name = $value2 ";
This will give you all rows for this user_id that have $value1 for location or have blank values.
I want to execute a parameterized query to perform a search by user-supplied parameters. There are quite a few parameters and not all of them are going to be supplied all the time. How can I make a standard query that specifies all possible parameters, but ignore some of these parameters if the user didn't choose a meaningful parameter value?
Here's an imaginary example to illustrate what I'm going for
$sql = 'SELECT * FROM people WHERE first_name = :first_name AND last_name = :last_name AND age = :age AND sex = :sex';
$query = $db->prepare($sql);
$query->execute(array(':first_name' => 'John', ':age' => '27');
Obviously, this will not work because the number of provided parameters does not match the number of expected parameters. Do I have to craft the query every time with only the specified parameters being included in the WHERE clause, or is there a way to get some of these parameters to be ignored or always return true when checked?
SELECT * FROM people
WHERE (first_name = :first_name or :first_name is null)
AND (last_name = :last_name or :last_name is null)
AND (age = :age or :age is null)
AND (sex = :sex or :sex is null)
When passing parameters, supply null for the ones you don't need.
Note that to be able to run a query this way, emulation mode for PDO have to be turned ON
First, start by changing your $sql string to simply:
$sql = 'SELECT * FROM people WHERE 1 = 1';
The WHERE 1 = 1 will allow you to not include any additional parameters...
Next, selectively concatenate to your $sql string any additional parameter that has a meaningful value:
$sql .= ' AND first_name = :first_name'
$sql .= ' AND age = :age'
Your $sql string now only contains the parameters that you plan on providing, so you can proceed as before:
$query = $db->prepare($sql);
$query->execute(array(':first_name' => 'John', ':age' => '27');
If you can't solve your problem by changing your query... There are several libraries that help with assembling queries. I've used Zend_Db_Select in the past but every framework likely has something similar:
$select = new Zend_Db_Select;
$select->from('people');
if (!empty($lastName)) {
$select->where('lastname = ?', $lastname);
}
$select->order('lastname desc')->limit(10);
echo $select; // SELECT * FROM people WHERE lastname = '...' ORDER BY lastname desc LIMIT 10
I've tested the solution given by #juergen but it gives a PDOException since number of bound variables does not match. The following (not so elegant) code works regardless of no of parameters:
function searchPeople( $inputArr )
{
$allowed = array(':first_name'=>'first_name', ':last_name'=>'last_name', ':age'=>'age', ':sex'=>'sex');
$sql = 'SELECT * FROM sf_guard_user WHERE 1 = 1';
foreach($allowed AS $key => $val)
{
if( array_key_exists( $key, $inputArr ) ){
$sql .= ' AND '. $val .' = '. $key;
}
}
$query = $db->prepare( $sql );
$query->execute( $inputArr );
return $query->fetchAll();
}
Usage:
$result = searchPeople(array(':first_name' => 'John', ':age' => '27'));