Firstly PHP doesn't deal brilliantly with GET/POST vars having the same name, each will overwrite the previous so you'll need something like:
<label>Volunteer: <input type="text" name="volunteer_id[0]" size="7" /></label>
<label>Position: <input type="text" name="position_id[0]" size="7" /></label>
<label>Memo: <textarea name="memo[0]" cols="45" rows="2"></textarea></label>
These should be indexed in the order received but to be on the safe side, in the code that generates your HTML you should add the index into the name (e.g. volunteer_id[0]) - empty <textarea> data doesn't get posted so you'll need to ensure it exists with the right index or you could end up with memos not lining up with volunteers/positions.
You can just loop a function to create your output; that will give you 3 arrays in $_POST when received by the PHP (I'm assuming your form method is "post"), like so:
//these will all be arrays
$aVolunteers = $_POST['volunteer_id'];
$aPositions = $_POST['position_id'];
$aMemos = $_POST['memo'];
Next, to build the query:
//how many volunteers are there
// - text input fields are always posted even when empty
// so counting volunteers should tell us how many data sets we've got
$iNumSets = count($aVolunteers);
//begin the query
$sQuery = "INSERT INTO work(volunteer_id, position_id, memo) VALUES";
//create an array of parameters to bind
$aBoundParams = array();
//loop to the total number of data sets
for($i = 0; $i < $iNumSets; $i++) {
//append the "values" to the query string
$sQuery .= "(?, ?, ?), ";
//add the values to the bound parameters array
// assumes the database fields are NULLable
$aBoundParams[] = !empty($aVolunteers[$i]) ? $aVolunteers[$i] : null;
$aBoundParams[] = !empty($aPositions[$i]) ? $aPositions[$i] : null;
//this one is the most important one to check !empty()
//as it's possible $aMemos[$i] doesn't exist
$aBoundParams[] = !empty($aMemos[$i]) ? $aMemos[$i] : null;
}
//trim the trailing ", "
$sQuery = substr($sQuery, 0, -2);
If your data sets were posted 3 times you should now have a query that looks like:
INSERT INTO work(volunteer_id, position_id, memo) VALUES(?, ?, ?), (?, ?, ?), (?, ?, ?)
And an array, length 9, like this:
array(
$aVolunteers[0],
$aPositions[0],
$aMemos[0],
$aVolunteers[1],
$aPositions[1],
$aMemos[1],
$aVolunteers[2],
$aPositions[2],
$aMemos[2]
)
You should now be able to prepare the query, bind the parameters/values and execute it.
//prepare the statement
$oStmt = $dbo->prepare($sQuery);
//bind the parameters to the statement
// parameters need to be bound by reference - note &$vParamValue
foreach($aBoundParams as $iParamIndex => &$vParamValue) {
$oStmt->bindParam(
//bound params/values are 1 indexed rather than 0
($iParamIndex + 1),
//value to bind
$vParamValue,
//basic variable type prep - assuming you're using PDO
(is_int($vParamValue) ? PDO::PARAM_INT : PDO::PARAM_STR)
);
}
//execute the statement
$oStmt->execute();