0

I have a form with several checkboxes. These boxes have one row each in a mysql db if checked. Now, I need to have a loop that build a query to delete all rows that is not checked. I tried the one below but the array is never populated... Any help is appreciated...

$chk_cab_1  = isset($_POST['chk_cab_1']) ?: 0;
$chk_cab_2  = isset($_POST['chk_cab_2']) ?: 0;
$chk_cab_3  = isset($_POST['chk_cab_3']) ?: 0;
$chk_cab_4  = isset($_POST['chk_cab_4']) ?: 0;
$chk_cab_5  = isset($_POST['chk_cab_5']) ?: 0;
$chk_cab_6  = isset($_POST['chk_cab_6']) ?: 0;
$chk_cab_7  = isset($_POST['chk_cab_7']) ?: 0;
$chk_cab_8  = isset($_POST['chk_cab_8']) ?: 0;
$chk_cab_9  = isset($_POST['chk_cab_9']) ?: 0;
$chk_cab_10 = isset($_POST['chk_cab_10']) ?: 0;
$chk_cab_11 = isset($_POST['chk_cab_11']) ?: 0;


$check_cab    = array();
$del_cab_ids  = array();
for($i = 1; $i<=$counter; $i++) {
    $check_cab["chk_cab_$i"]     = $chk_cab_$i;
    if($check_cab["chk_cab_$i"] == 0) {
       $del_cab_ids[] = $i;
    }
}

$sql = "DELETE FROM mytable 
        WHERE first_id = $t_key
        AND second_id IN ($del_cab_ids)";
1
  • 3
    You can use <input name="chk_cab[5]" type="checkbox" value="1" /> so that you get an array immediately. Commented Mar 6, 2014 at 8:47

5 Answers 5

2

I would change the HTML, if possible to rename the checkboxes like this:

<input name="chk_cab[0]" type="checkbox" value="1" />
...
<input name="chk_cab[5]" type="checkbox" value="1" />
...

And then invert the query:

$sql = "DELETE FROM mytable WHERE first_id = ?";

if (isset($_POST['chk_cab']) {
    $ids = join(',', array_map('intval', array_keys($_POST['chk_cab'])));

    $sql .= " AND second_id NOT IN ($ids)";
}

Important: This assumes that all entries matched by first_id = <whatever> are accounted for within [1 .. $counter].

Sign up to request clarification or add additional context in comments.

2 Comments

Wrt "inverting the query"; it's not strictly semantically equivalent and could delete data erroneously here -- A case might be made that this would be a better solution overall, but I would rather keep the approach the same as in the original to avoid issues (e.g. "phantom deletes") with concurrency.
@user2864740 While that is technically possible; the query is limited by the first part of the query; in any case, I've updated the answer to make OP stop and think first.
1

Create an array at the start. This avoids nonsense with "variable variables"1

$del_cab_ids = array();
for($i = 1; $i<=$counter; $i++) {
   # it's easier/cleaner to use a dynamic key than a dynamic variable
   $v = isset($_POST['chk_cab_' . $i]) ?: 0;
   if ($v == 0) {
     $del_cab_ids[] = $i;
   }
}

Also, at least use mysqli_real_escape_string .. but I recommend using placeholders and binding the values ..


1 While I don't agree with "variable variables", the usage is as such:

$varname = "chk_cab_" . $i;
$value = $$varname;

# or
$value = ${"chk_cab_" . $i}

Comments

1

Try this....

$check_cab["chk_cab_$i"] = ${'chk_cab_'.$i}

Comments

1

The complete structure seems to be a bit ... ugly. Sorry for that. ;) So you can avoid that mass of unnecessary variables by using a simple array for your post data.

<input type="checkbox" value="1" name="my-checkbox[]" id="my-checkbox-1" /> 1
<input type="checkbox" value="2" name="my-checkbox[]" id="my-checkbox-2" /> 2

With this you can grab all the IDs in one simple line of PHP code as follows:

if (isset($_POST['my-checkbox'])) $myIDs = array_map('intval', $_POST['my-checkbox']);

So all your post IDs have been validated as an integer value so you can proceed with your database statement. For this I recommend using statements like the PDO object gives you with PDO Statements to avoid security issues. Have a look at the following example:

try {
    $pdo = new PDO(...);
    $sql = "DELETE FROM mytable WHERE first_id = :first_id AND FIND_IN_SET(CAST(second_id AS char), :second_id)";

    $statement = $pdo->prepare($sql);
    $statement->execute(array(
        ':first_id' => $first_id,
        ':second_id' => implode(",", $myIDs)
    ));
} catch(PDOException $e) {
    // error handling
}

That 's all. With this small example all your structure and security problems should have been solved.

5 Comments

I 'm always open for advice. Where 's the sql injection problem in your eyes?
Whoops, that was wrong (binding prevents the SQL injection) .. but does this even work? I would expect passing in a CSV string as as placeholder value would not.
Yes, this even works. You 've validated the post data before with intval() and after that pdo does even an extra escaping with in the statement. This works fine. ;)
I mean, why/how is does this placeholder (:second) result in .. IN ('1','2','3') and not .. IN ('1,2,3')?
Just tested it on my localhost, cos I was not quite sure. But it works perfectly. The placeholder is not replaced as a string. Just fine, comma seperated integer values. ;)
0

Try:

$del_cab_ids = implode(',', $del_cab_ids);
$sql = "DELETE FROM mytable 
    WHERE first_id = $t_key
    AND second_id IN ($del_cab_ids)";

4 Comments

Your code doesn't even mention the horrible SQL injection vulnerability this solution has.
Second Ricudo, I was pointing why his query was having problems executing.
When i give examples for SQLs, i neither write it perfectly save. The examples are only for giving a hint into the right direction, not just copy and paste.
I am aware of the SQL injection issue. I wrote the sql to show in a simple way how I will use the array.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.