I think a quick review of bitwise operations is in order here
What you are attempting to do is use binary, so…
0000:0001 = 1
0000:0010 = 2
0000:0100 = 4
0000:1000 = 8
and so on and so forth. the & operation (and) does this:
0001 & 0001 == true
0010 & 0010 == true
0011 & 0001 == true
0011 & 0010 == true
0010 & 0001 == false
There’s an operation called “shifts” – in php they are indicated by << and >>
A shift left by one is the same as multiply by two… but two is four, etc, etc…
0001 << 2 == 0100
0010 << 1 == 0100
0100 >> 2 == 0001
Which just quickly sums up what needs to be done here for operations.
To handle all this for a form, I’d probably make a object with the various things you need to do as methods. What ‘needs to be done’? Well, a constructor which gets passed the common ‘name’ for all the fields, the labels for all the fields, and the starting integer value you’re storing these ‘flags’ in. That’s the PROPER term for this by the way, flags/bitFlags. Each bit is a ‘flag’… from there a routine to populate from the $_POST data if need be – you flop them on validation, it helps to be able to re-send what they set so they don’t have to re-enter everything… then a routine to automatically build the labels/inputs for you, and last of all a getFlags function to pull the current state as that nice packed integer.
class checkBoxListHandler {
private
$prefix,
$list=array();
public function __construct($prefix,$list,$flags=0) {
$this->prefix=$prefix;
foreach ($list as $key => $value) {
$bitMask=1 << $key;
$this->list[$key]=array(
'label' = $value,
'checked' => $flags & $bitMask,
'bitmask'= $bitMask
);
}
} // function __construct
public function populateFromForm() {
foreach ($this->list as $key => $value) {
/*
we have to iterate $this->list because unchecked boxes
often are not returned by some browsers as results!
*/
$this->list[$key]['checked']=(
isset($_POST[$this->prefix][$key]) ?
$_POST[$this->prefix][$key] :
0
);
}
} // function populateFromForm
public function showForm() {
foreach ($this->list as $key => $data) {
echo '
<label for="',$this->prefix,$key,'">',$data['label'],'</label>
<input
type="checkbox"
id="',$this->prefix,$key,'"
name="',$this->prefix,'[',$key,']','"
value="',$data['bitMask'],'"',(
$data['checked']==0 ? '' : ' checked="checked"'
),'
/>
<br />';
}
} // function showForm
public function getFlags() {
$result=0;
foreach ($this->list as $data) {
$result=$result & $data['checked'];
}
return $result;
} // function getFlags
} // class checkBoxListHandler
Untested, probably a typo or two, but you get the idea…
To create the object you’d simply pass it thus:
$myCheckboxList=new checkBoxListHandler(
'mychecks',
array(
'first checkbox','second checkbox','third checkbox'
),
$startingPackedFlags
);
StartingPackedFlags being whatever you pull from the database, and is optional so if you’re working from the value already in your database (edit) you can handle it there… if you came from the form and rejected it, or if you are showing a new one, all you’d have to do is:
$myCheckBoxList->showForm();
and poof, there are all your labels/inputs
<label for="mychecks_0">first checkbox</label>
<input
type="checkbox"
id="mychecks0"
name="mychecks[0]"
value="1"
/>
<br />
<label for="mychecks_1">second checkbox</label>
<input
type="checkbox"
id="mychecks1"
name="mychecks[1]"
value="2"
/>
<br />
<label for="mychecks_2">third checkbox</label>
<input
type="checkbox"
id="mychecks2"
name="mychecks[2]"
value="4"
/>
<br />
When returning from a form, you just create the object and then call:
$myCheckBoxList->populateFromForm();
$checkFlags=$myCheckBoxList->getFlags();
I prefer to use the same php file to handle returns from forms as I do sending the form, so an generic ‘overview’ of such a file would probably go:
$myCheckboxList=new checkBoxListHandler(
'mychecks',
array(
'first checkbox','second checkbox','third checkbox'
),
$startingPackedFlags
);
if isset($_POST['fromForm']) {
$myCheckBoxList->populateFromForm();
if (validateForm) {
$checkFlags=$myCheckBoxList->getFlags();
/* write it to the database here */
} else $myCheckBoxList->showForm();
} else $myCheckBoxList->showForm();
That’s just a generic overview – you’d have a lot more going on in there, but you should get the general logic of how that object works from that.
Oh, and a little hint – assuming you’re using integer that’s typically a 32 bit variable, so you can only stuff 32 checkboxes into your one ‘flags’ variable. Also my object is ‘tied’ to the key order, so if you change the order of the array, it’ll mess up. Should you need control over the order, you can pass the array key manually thus:
$myCheckboxList=new checkBoxListHandler(
'mychecks',
array(
1 => 'first checkbox',
0 => 'second checkbox',
5 => 'third checkbox'
),
$startingPackedFlags
);
Which will show them in order and populate their flags properly… using the shifts internally means you can pass any number 0…31 as your key… in any order.
A more robust version might used named keys and a counter – the ‘name’ could be used instead of prefix (or with it) and might be easier to work with server-side than numbers.
Oh, @anthony – you know printF is slow as molasses, and your isChecked function adds pointless overhead to the code right? (two conditionals and a function call for what should be a single conditional?!?). I mean, I could see it if multiple operations were being performed, but a single binary “and”?!?