implode() [function.implode]: Invalid arguments passed WHEN $_POST['duration'] == EMPTY - php

I have a multiselect field
<select name="duration[]" id="duration" title="Duration" multiple="multiple" size="3">
<option value="1">1 Months</option>
<option value="2">2 Months</option>
<option value="3">3 Months</option>
</select>
my php code implode multiple values i.e 123 as 1,2,3 and insert it in database. The problem is that the field is not a required field and when i leave it empty it give me error (Invalid arguments passed)
My php code below
$duration = array();
$duration = $_POST['duration'];
if($duration)
{
foreach($duration as $value)
{
$months[] = $value;
}
}
$sql = "SELECT * FROM tbl_courses WHERE duration IN (".implode($months, ',').") ";
thanks in advance

The two problems you have is you try to implode on user input which may not be an array, and your code is vulnerable to SQL Injection.
To address those you should first check if it's an array with is_array(), then check if it has any elements with count(), then finally implode but use array_map() to filter the values to prevent SQL Injection. This will not only prevent SQL Injection but will prevent syntax errors in your query because strings must be quoted in an IN clause.
function getInt($i) {
return (int)$i;
}
$inClause = '';
if(isset($_POST['duration']) && is_array($_POST['duration']) && count($_POST['duration']) > 0)
{
$inClause = 'WHERE ';
$inClause .= implode(', ', array_map('getInt', $_POST['duration']));
}
$sql = "SELECT * FROM tbl_courses $inClause";

$duration = array();
$duration = $_POST['duration'];
$sql = FALSE;
if($duration&&is_array($duration))
{
foreach($duration as $value)
{
$months[] = $value;
}
$sql = "SELECT * FROM tbl_courses WHERE duration IN (".implode($months, ',').") ";
}
if($sql){
//do something with sql
}
use is_array to check if $duration is an array.

Just remove the WHERE condition if it is not required
$sql = "SELECT * FROM tbl_courses";
if (count($months)>0)
$sql .= " WHERE duration IN (".implode($months, ',').") ";
and better use isset($_POST["x"]) instead of just an if.

So let's say $_POST['duration'] is null.
$duration = array();
$duration = $_POST['duration'];
Then you don't have a value to implode on because your foreach is not going to be executed.
One solution would be to put your code into an if( $_POST['duration'] ) respectively if( count($months) )

One of options is typecasting.
$duration = (array)$_POST['duration'];
Since you use contents of $_POST['duration'] in your query be aware of SQL injection techniques.

Check that $_POST['duration'] is set and build your WHERE statement if it is, if not leave it blank:
$where = !$_POST['duration'] ? '' : 'WHERE duration IN ('.implode($_POST['duration'],',').')';
$sql = 'SELECT * FROM tbl_courses '.$where;
I have also removed some of your unnecessary variable declaration and looping around $duration.
Please note you need to sanitise your data to protect against SQL injection. The easiest way in this case would to be to loop through the values and cast them as int:
foreach($_POST['duration'] as $value) {
$months[] = (int)$value;
}
$where = !$months ? '' : 'WHERE duration IN ('.implode($months,',').')';
$sql = 'SELECT * FROM tbl_courses '.$where;

Related

Send only filled inputs values to database via SQL

I have dozens of inputs in an HTML table one can use to enter numerical values. When submit button is pressed all inputs values are added to their corresponding column in the SQL table via post method. Value of <input name="A1> will be sent to column A1 in SQL table, <input name="A2> to column A2, and so on.
I'm currently using something like this (but with dozens of parameters) to insert data in my table :
$sql = "INSERT INTO all_stats_table (A1, A2, A3) VALUES ($A1, $A2, $A3)";
Problem with this approach is that every input needs to be filled or it will result in an SQL error. I initially used php to set all empty inputs value to 0 before sending everything to database, but I don't think this method is the most efficient way to go.
I would rather like to dynamically check which inputs are actually filled and only send their values to the table instead of converting every empty input value to 0 and having to send everything to the database.
I've already set all default values to 0 in SQL, but I don't know how to only send filled input values via SQL. I tried using a php foreach loop but I'm definitely having trouble finding the right SQL syntax.
Is what I'm trying to do possible ? If not, what would be the best practice to make this process more efficient ?
Thank you for your help
EDIT : attempt to adapt akash raigade's great solution to non-numbered SQL columns :
HTML :
<input name='name'>
<input name='address'>
<input name='age'>
PHP :
$Field_list = array ('name','address','age');
$field_string = '';
$input_string = '';
foreach ($_POST as $userInfo=>$userInfo_value) {
if (isset($userInfo)) {
if ($field_string == '') {
$field_string = $field_string.$userInfo; //problem here ?
$input_string = $userInfo_value; //problem here ?
}
else {
$field_string = $field_string.','.$userInfo; //problem here ?
$input_string = $input_string.','.$userInfo_value; //problem here ?
}
}
}
$sql = "INSERT INTO protocole_test (".$field_string.") VALUES (".$input_string.")";
echo $sql ; //check query formed
[Upgraded version]
Basic idea is that we keep NAME attribute of INPUT same as table column-name where it is gonna be stored.Then with help of input tag name and value which are filled we prepare SQL statement which have only required (FILLED) columns and values.
For given example consider following MYSQL table :
sr.no.|name|age|gender
CODE [Tested]:
<input name="name" >
<input name="age" >
<input name="gender" >
<input type='submit'>
<?php
$field_string ='';
$input_string='';
foreach ($_POST as $userInfo=>$userInfo_value){
if($userInfo_value !=''){
echo $userInfo."->".$userInfo_value;
if ($field_string == '') {
$field_string = $field_string.$userInfo;
$input_string = $userInfo_value;
}
else {
$field_string = $field_string.','.$userInfo;
$input_string = $input_string.','.$userInfo_value;
}
}
}
$sql = "INSERT INTO protocole_test (".$field_string.") VALUES (".$input_string.")";
echo $sql ; //check query formed
?>
[original answer]Have a look at following code :
<input name='a1' id='input_for_name'>
<input name='a2' id='input_for_class'>
<input name='a3' id='input_for_seat.no'>
.
.
<input name='an' id='input_for_n'>
Now
<?php
//you must be having field list to be inserted i.e
//INSERT INTO all_stats_table >>>(A1, A2, A3)<<< VALUES ($A1, $A2, $A3)
//A1,A2,A3 is field list here
//so save them into an array.
$Field_list = array ('A1','A2','A3',.......'An');
//Now get which input_field is inputted by :
$i=0;
$field_string = '';
$input_string = '';
for($i<n){
if(isset($_POST['a'.$i])){
if ($field_string == ''){
$field_string = $field_string.$Field_list[$i];
$input_string = $_POST['a'.$i];
}
else {
$field_string = $field_string.','.$Field_list[$i];
$input_string = $input_string.','.$_POST['a'$i];
}}}
$sql = "INSERT INTO (".$field_string.") VALUES (".$input_string.")";
//to check query formed
echo $sql ;
?>
Explanation :
We check which input field is FILLED , if it is field we add its FIELD into FIELD LIST and ITS VALUE in INPUT LIST finally we GENERATE SQL STATEMENT.
Just check if they are not defined or empty, and if so, define them.
if ( (!isset($_POST['A1'])) || (empty($_POST['A1']) ){
$A1 = '0';
} else {
$A1 = $_POST['A1'];
}
I'm not able to test this and it may need some debugging, but you could create a function, then call the function for each input. Something like...
function chkinput($input){
if ( (!isset($_POST[$input])) || (empty($_POST[$input]) ){
$$input = '0';
} else {
$$input = $_POST[$input];
}
return $$input;
}
// You could potentially loop through the post array
// but here I just call the function once per input
chkinput('A1');
chkinput('A2');
...
chkinput('A12');
You loop through the $_POST array and check if it has a value. If it does concatenate it to an variable. Like this:
$fields = "";
$values = "";
foreach($_POST as $key=>$value){
if($value != ''){
if($value != end($_POST)){
$fields .= $key . ", ";
$values .= "'" . $value . "', ";
}else{
$fields .= $key;
$values .= "'" . $value . "'" ;
}
}
}
$sql = INSERT INTO protocole_test ($fields) VALUES ($values) ;
Your SQL would look like :
INSERT INTO protocole_test (A1, A2, A3) VALUES ('A1', 'A2', 'A3')

search dynamically PHP MYSQL PDO

I have a form with 3 select boxes: age,room,type.
<form action="results.php" method="get">
<div class="form-group">
<select name="age">
<option value>Any</option>
<option value="1">15</option>
<option value="2">25</option>
<option value="3">30</option>
<option value="4">40</option>
</select>
</div>
<div class="form-group">
<select name="room">
<option value>Any</option>
<option value="1">1</option>
<option value="2">2</option>
</select>
</div>
<div class="form-group">
<select name="type">
<option value>Any</option>
<option value="1">Personal</option>
<option value="2">Business</option>
</select>
</div>
</form>
What i am trying to do with PDO is to make a small search.
If all variables are empty then my condition is:
$search = $db->query("SELECT * FROM table");
If 1 of them (as example the age) is not empty then i have:
if(!empty($_GET['age'])){
$age = $_GET['age'];
$search = $db->query("SELECT * FROM table WHERE age = '$age'");
}
Now, if 2 of them are npt empty i have:
if(!empty($_GET['age']) && !empty($GET['room'])){
$age = $_GET['age'];
$room = $_GET['room'];
$search = $db->query("SELECT * FROM table WHERE age = '$age' AND room = '$room'");
}
In order to avoid all possible search combinations, how can i make a search with the term if is not empty. I had made one in the past:
if(!empty($age)){
$where = "WHERE age = '$age'";
}
if(!empty($room)){
$where .= "and room = '$room'";
}
$query = "SELECT * FROM table $where";
How can i make it happen with PDO?? :/
I'd do something like this:
$param = array();
$query = 'SELECT ... FROM t WHERE 1=1';
if(!empty($_GET['age'])){
$param['age'] = $_GET['age'];
$query .= ' AND t.age = :age';
}
if(!empty($_GET['room'])){
$param['room'] = $_GET['room'];
$query .= ' AND t.room = :room';
}
if(!empty($_GET['type'])){
$param['type'] = $_GET['type'];
$query .= ' AND t.type = :type';
}
$dbh->prepare($query)->execute($param);
You might want to separate out the prepare and the execute. Check the return from the prepare before you try calling execute. Or, configure PDO can throw an exception when an error occurs, e.g.
$dbh->setAttribute(PDO::ERRMODE_EXCEPTION);
You will need to make a query builder of some kind. You will also want to use prepared statements, rather than directly injecting user-provided input into the sql query. That might look something like this:
<?php
$search = [
'age' => 42,
'room' => 'Millyway',
];
$criteria = [];
$params = [];
foreach($search as $field => $value) {
$criteria[] = "$field = :$field";
$params[$field] = $value;
}
$where = ($criteria ? ('WHERE ' . implode(' AND ', $criteria)) : '');
$query = "SELECT * FROM tablename $where";
$stmt = $db->prepare($query);
$stmt->execute($params);
while($obj = $stmt->fetchObject()) {
// iterate over your result set
}
Given search terms as key-values in $search (which can be any column and value in the table, and will need to be populated from wherever those values come from), this code will build $criteria, a set of WHERE clause fragments (using a parameterized sql parameter name, rather than injecting the value directly), and $params, the list of parameters to be passed into the (upcoming) prepared statement.
It then builds the full WHERE clause in $where, by either combining all of the $criteria that were built, or returning an empty string. This is then added directly into the query, and the query is executed using the parameters array that was built up. You then iterate over the result set like any other PDO query.
Among others, the main benefit of using parameterized SQL over injecting variables directly is that it protects you from SQL Injection attacks.
Note that there are many ways this code could be improved. You could easily put it in a function; add complexity to allow for different types of comparisons (e.g. <> or LIKE); even use it as the basis for a more complicated query builder that allows more complicated logic such as ((age = :age AND room = :room1) OR (room = :room2)); and so on. What you do is up to the needs of your application.

Having difficulty to concatenate condition and $_POST variables inside a variable

I would like to add this line of code
<?php echo(isset($_POST['AgentID'])&&($_POST['AgentID']=='')?' selected="selected"':'');?>
inside
$agentData.='<option value="'.$row['AgentID'].'">'.$row['AgentID'].' - '.$row['AgentName'].'</option>';
I'm having difficulty because of " " and ' ' due to $_POST variables has ' ' also
The whole code is:
<select name="AgentID" id="agentIDSentakushi">
<option value="" <?php echo(isset($_POST['AgentID'])&&($_POST['AgentID']=='')?' selected="selected"':'');?>>--</option>
<?php
$setsu = dbSetsuzoku();
$sql = 'SELECT AgentID,AgentName FROM agentdb ORDER BY AgentID';
$agentData='';
$result = $setsu->query($sql);
while ($row = $result->fetch(PDO::FETCH_ASSOC))
{
$agentData.='<option value="'.$row['AgentID'].'">'.$row['AgentID'].' - '.$row['AgentName'].'</option>';
}
echo $agentData;
$setsu = null;
?>
</select>
To simplify it, do:
while ($row = $result->fetch(PDO::FETCH_ASSOC))
{
$selected = (isset($_POST['AgentID']) && $_POST['AgentID']==$row['AgentID'])?'selected="selected"':'';
$agentData.='<option value="'.$row['AgentID'].'"'.$selected.'>'.$row['AgentID'].' - '.$row['AgentName'].'</option>';
}
$selected here is a variable which checks if $_POST['AgentID'] is set and if it's equal to $_POST['AgentID'], if the conditions are true, that option will be selected.
I'd go about is using vsprintf like this:
$setsu = dbSetsuzoku();
$sql = "
SELECT
AgentID,
AgentID AS AgentID_2, -- notice how I duplicated it here
AgentName
FROM agentdb
ORDER BY AgentID
";
$agentData = '';
$result = $setsu->query($sql);
while ($row = $result->fetch(PDO::FETCH_ASSOC))
{
$selected = (isset($_POST['AgentID']) && $_POST['AgentID'] == $row['AgentID']) ? ' selected' : '';
$agentData .= vsprintf("<option value='%d'$selected>%d - %s</option>", $row);
}
echo $agentData;
$setsu = null;
The trick here is to select the parameters you will then later print in the same order (and quantity) in the SQL query since you will pass the returned array directly to vsprintf and the array returned from the SQL query needs to be in the same order as your vsprintf placeholders. Saves you a lot of confusing text :)

PHP variable used in SQL

My code checks if there is $GET value, if not then assign ALL values of array.
Seems like simple thing,not sure why its not working.
if(isset($_GET["smonth"])) {$smonth= $_GET["smonth"];
}
else {$smonth =12;} working , but not what I want
else {$smonth =array (1,2,3,4,5,6,7,8,9,10,11) ;}
After that I would like to use it in SQL :
and d.month_of_year = '".$smonth."%'
That would be something like
and month_of_year = (all values of array) or 1 value)
My Question:
What would be best solution to check, if active month is available? If not, assign All months to query.Thank You
The built-in PHP functions of in_array and implode should solve your issue:
in_array('1', $_GET["smonth"]); // checks if January is in $_GET["smonth"]
implode("," , $_GET["smonth"]); // Pull all of the values out of $_GET["smonth"] as a A STRING
Try in your statement and d.month_of_year IN (" . implode(',', $smonth) . ")
= operator checks for single value. If you want to check multiple values, use in.
and d.month_of_year in (".$smonth.")
You also have a % there, which works with LIKE queries.
<?php
if(isset($_GET['month'])){
$month = date('m'); //This would give you the index of the current month.
$array = array('01','02','02');
$query = "select * from table where month = ";
if(in_array($month,$array)){
$query = "select * from table where month = '".$month."'";
//Then query here
}
else
{
$query = "select * from table";
$where = "";
foreach($month as $m){
$where .= ' month = "'.$m.'" and ';
}
//There would be a ending and pls just try remove it
$query .= $where;
// then query here
}
}
?>

PHP: building query from array foreach

$test=$_POST['Cities'];
foreach ($test as $t){
$query .= " AND u.bostadsort = \'".$t."\'";
}
I have this for my
<select size="6" name="Cities[]" multiple="multiple">
<option value="">All</option>
<option value="1">C1</option>
<option value="2">C2</option>
<option value="3">S3</option>
<option value="4">S4</option>
<option value="5">S5</option>
</select>
But its not right at all.
What I'm trying to do is when you pick the cities(in the search form), it puts all the values into an array.
Now I would like to have it write like this, if you e.g pick 2, 4, 5
AND u.bostadsort = '2' OR u.bostadsort = '4' OR u.bostadsort = '5'
(maybe you could do this easier to, but this is the only way i know, using "OR")
So if you picked more than 1 then it should be OR, instead of the AND i got.
Maybe I done it in a wrong way, and there is a better method doing this than foreach..
How can I do this?
You could use IN instead, which lets you supply multiple values:
if (is_array($_POST['Cities']))
{
// If multiple values were selected, handle them
$cities = array();
foreach ($_POST['Cities'] as $city)
{
if (!empty($city))
{
$cities[] = mysql_real_escape_string($city);
}
}
}
elseif (!empty($_POST['Cities']))
{
// ... or was a single, non-empty value passed in?
$cities = array(mysql_real_escape_string($_POST['Cities']));
}
if (count($cities))
{
$query .= " AND u.bostadsort IN ('" . join("', '", $cities) . "')";
}
Note that I am passing each value through mysql_real_escape_string before using it in the query; this is done to prevent SQL injection. If you are not using MySQL, the other RDBMSes have similar functions.
See http://www.ideone.com/UVXuu for an example (ideone doesn't seem to have mysql enabled, so the calls to mysql_real_escape_string are removed).
Alternately, you could use PDO's prepare and execute methods:
$cities = $_POST['Cities'];
if (count($cities))
{
$query .= " AND u.bostadsort IN (?" . str_repeat(', ?', count($cities) - 1) . ")";
}
// $db is a PDO object
$stmt = $db->prepare($query);
$stmt->execute($cities);
(Of course, this solution ignores how you build the rest of your query because you don't give it in your question, so you'd want to parameterize the other parts as well.)

Categories