Jump to content

enetering empty fields


I-AM-OBODO
Go to solution Solved by mac_gyver,

Recommended Posts

Hello all.

I have worked my head out but i cant seem to figure out why i am getting error/entering empty stings. I have tried different things but none seems to work as expected. i know the problem is from the array field validation but cant seem to figure out how to get it done. If i submit without entering any field, the error works fine. But if i fill only one field, it gives error and saves empty strings.

 

Thanks

if(isset($_POST['submit'])) {

$test_score = $_POST['test_score'][0];
$exam_score = $_POST['exam_score'][0];

if(empty($test_score)) {
$error['test_score'] = "Test Score Field is Required";
}if(empty($exam_score)) {
$error['exam_score'] = "Exam Score Field is Required";
}

if(empty($error)) {

foreach ($_POST['subject'] as $key => $value) {

$sql = "INSERT INTO $table_name(
subject, 
test_score,
exam_score
) 
VALUES(
:subject,
:test_score, 
:exam_score
)";

$stmt = $pdo->prepare($sql);
$stmt->execute([
'subject' => $value,
'test_score' => $_POST['test_score'][$key],
'exam_score' => $_POST['exam_score'][$key]
]);                                                        
}
if($stmt->rowCount()){

echo '<div class="alert alert-success text-center">Data Saved</div>';

}else{
  
echo '<div class="alert alert-danger text-center">Data Not Saved</div>';
}

}else{
echo '<br><div class="alert alert-danger text-center">Fields Empty!</div>';
}

}

//my form

<table class="table table-borderless">
<thead>
<tr>
<th>SN</th>
<th>Subject</th>
<th>Continuous Assesment Score</th>
<th>Examination Score</th>
</tr>
</thead>
<tbody>
<div>
<form action="" method="post">
<?php

$i = 1;
$stmt=$pdo->query("
SELECT subjects
FROM tbl_subjects_secondary
");

WHILE($row = $stmt->fetch(PDO::FETCH_ASSOC)){

?>

<tr>
<th><?php echo $i++ ?></th>
<td><input type="text" name="subject[]" class="form-control border-0" readonly value="<?php if(isset($row['subject_name'])) { echo $row['subject_name']; } ?>"></td>
<td><input type="number" name="test_score[]" class="form-control"><span style="color: red; font-size: .8em;"><?php if(isset($error['test_score'])){ echo $error['test_score'];} ?></span></td>
<td><input type="number" name="exam_score[]" class="form-control"><span style="color: red; font-size: .8em;"><?php if(isset($error['exam_score'])){ echo $error['exam_score'];} ?></span></td>
</tr>                        

<?php
  }
?>

<tr>
<td></td><td></td>
<td colspan="2"><button type="submit" name="save" class="btn btn-primary w-50">Save</button></td>
</tr>
</form>
</div>
</tbody>
</table>

 

Link to comment
Share on other sites

$test_score = $_POST['test_score'][0];
$exam_score = $_POST['exam_score'][0];

if(empty($test_score)) {
$error['test_score'] = "Test Score Field is Required";
}if(empty($exam_score)) {
$error['exam_score'] = "Exam Score Field is Required";
}

You are only checking the first input with that code.  Since your form can contain multiple inputs for those fields, you need to check all of the inputs if that is what you want to require.

Here is an example for one of the inputs:

$allEmpty = true;
foreach ($_POST['exam_score'] as $input){
    $allEmpty = $allEmpty && empty($input);
}
if ($allEmpty){
   $error['exam_score']='Exam score is required.';
}

Ideally, you would also validate that the input is numeric (see ctype_digit) as well.  Using input type=number does not guarantee the input will be numeric (no client-enforced rule is guaranteed).

Link to comment
Share on other sites

here's my typical laundry list of points for the posted code -

  1. you should not attempt to detect if a submit button is set. there are cases where it won't be. just detect if a post method form was submitted.
  2. you should trim all input data before validating it.
  3. you should validate all inputs separately, storing validation errors in an array using the field name as the main array index. since you have a set of inputs for each field name, you would also use the $key as a second index when storing validation errors.
  4. by validating the inputs separately, you can eventually get your logic attempting to display the errors adjacent to the corresponding field to work.
  5. after the end of the validation logic, if there are no errors (the $error array will be empty), use the submitted data.
  6. $table_name - if you are creating a bunch of different tables to hold this data, you should instead have one table with a column that identifies what is different about each set of data.
  7. the subject column in the table holding the submitted data should be the subject id, not the subject name.
  8. you should prepare the query once, before the start of the looping.
  9. it will be a poor user experience if you produce an alert for every row that gets inserted. you should instead store any result message in an array using the $key as the array index, then test/use the contents of this array, after the end of the looping.
  10. for this query, the data will be inserted unless there is a query error. most query errors are due to programming mistakes that won't occur once you have tested and debugging your application. you should use exceptions for database statement error handling. this is now the default  setting in php8+. if this query can produce errors due to duplicate or out of range user submitted values, you would catch the database exception from it, test if the error number is for something that your code is handling, and setup error messages (add to the $error array) letting the user know what was wrong with the data that they submitted. for all other error numbers, just rethrow the exception and let php handle it.
  11. since this data is a set, this INSERT query should be part of a transaction, that will get rolled back if there are any errors for any of the inserts.
  12. you need to validate the resulting web pages at validator.w3.org, e.g. you can put a html table inside a form and you can put a form inside a single html table cell, but you cannot spread a form out inside a html table. an empty action='' attribute is not valid html5. just leave the action attribute out to get the form to submit to the same page it is on.
  13. the code producing the output is using 'subject_name', not 'subjects' and you would not test if it isset() to echo it, since this is the whole point of this code. it must be set or you have a programming mistake somewhere.
  14. there should be a subject id, and this should be used when storing the submitted data. you would either have a separate hidden array field for the ids or you would use the ids as the index for the existing array fields.
  15. if you set the default fetch mode to assoc when you make the database connection, you won't have to specify it in each fetch statement.

 

Edited by mac_gyver
Link to comment
Share on other sites

22 hours ago, kicken said:
$test_score = $_POST['test_score'][0];
$exam_score = $_POST['exam_score'][0];

if(empty($test_score)) {
$error['test_score'] = "Test Score Field is Required";
}if(empty($exam_score)) {
$error['exam_score'] = "Exam Score Field is Required";
}

You are only checking the first input with that code.  Since your form can contain multiple inputs for those fields, you need to check all of the inputs if that is what you want to require.

Here is an example for one of the inputs:

$allEmpty = true;
foreach ($_POST['exam_score'] as $input){
    $allEmpty = $allEmpty && empty($input);
}
if ($allEmpty){
   $error['exam_score']='Exam score is required.';
}

Ideally, you would also validate that the input is numeric (see ctype_digit) as well.  Using input type=number does not guarantee the input will be numeric (no client-enforced rule is guaranteed).

Thanks. But its same behavior like mine. If nothing is inputted, the validation works but when you fill the first subject, the other empty fields will be saved as empty!

I guess i'd have to change the way the form fields are displayed. instead of getting the subjects from the database, i guess i will just create them in a form, with this way, the validation will/should work!

Edited by I-AM-OBODO
Link to comment
Share on other sites

21 hours ago, mac_gyver said:

here's my typical laundry list of points for the posted code -

  1. you should not attempt to detect if a submit button is set. there are cases where it won't be. just detect if a post method form was submitted.
  2. you should trim all input data before validating it.
  3. you should validate all inputs separately, storing validation errors in an array using the field name as the main array index. since you have a set of inputs for each field name, you would also use the $key as a second index when storing validation errors.
  4. by validating the inputs separately, you can eventually get your logic attempting to display the errors adjacent to the corresponding field to work.
  5. after the end of the validation logic, if there are no errors (the $error array will be empty), use the submitted data.
  6. $table_name - if you are creating a bunch of different tables to hold this data, you should instead have one table with a column that identifies what is different about each set of data.
  7. the subject column in the table holding the submitted data should be the subject id, not the subject name.
  8. you should prepare the query once, before the start of the looping.
  9. it will be a poor user experience if you produce an alert for every row that gets inserted. you should instead store any result message in an array using the $key as the array index, then test/use the contents of this array, after the end of the looping.
  10. for this query, the data will be inserted unless there is a query error. most query errors are due to programming mistakes that won't occur once you have tested and debugging your application. you should use exceptions for database statement error handling. this is now the default  setting in php8+. if this query can produce errors due to duplicate or out of range user submitted values, you would catch the database exception from it, test if the error number is for something that your code is handling, and setup error messages (add to the $error array) letting the user know what was wrong with the data that they submitted. for all other error numbers, just rethrow the exception and let php handle it.
  11. since this data is a set, this INSERT query should be part of a transaction, that will get rolled back if there are any errors for any of the inserts.
  12. you need to validate the resulting web pages at validator.w3.org, e.g. you can put a html table inside a form and you can put a form inside a single html table cell, but you cannot spread a form out inside a html table. an empty action='' attribute is not valid html5. just leave the action attribute out to get the form to submit to the same page it is on.
  13. the code producing the output is using 'subject_name', not 'subjects' and you would not test if it isset() to echo it, since this is the whole point of this code. it must be set or you have a programming mistake somewhere.
  14. there should be a subject id, and this should be used when storing the submitted data. you would either have a separate hidden array field for the ids or you would use the ids as the index for the existing array fields.
  15. if you set the default fetch mode to assoc when you make the database connection, you won't have to specify it in each fetch statement.

 

Thanks. In the code proper, i did validation for the inputs. i did not include the validation while posting. some things you mention are done in the code proper but overall i learnt some interesting things from your list. thanks again

Link to comment
Share on other sites

  • Solution
1 hour ago, I-AM-OBODO said:

i did not include the validation while posting

if you are not posting the actual code that you are having a problem with, the replies you get may not have anything to do with the problem.

here's example code (tested with faked data from the SELECT query) showing most of the points that i made -

<?php

// initialization

// recursive trim function
function _trim($val)
{
	if(is_array($val))
	{
		return array_map('_trim',$val);
	} else {
		return trim($val);
	}
}

session_start();

// make database connection here...

$table_name = 'your_table';

$error = []; // an array to hold user/validation errors
$post = []; // an array to hold a trimmed working copy of the form data

// get all subject data
$sql = "SELECT id, subject_name FROM tbl_subjects_secondary";
$stmt=$pdo->query($sql);
$subject_data = $stmt->fetchAll();


// post method form processing
if($_SERVER['REQUEST_METHOD'] === 'POST')
{
	// trim all the input data at once
	$post = _trim($_POST);
	
	// loop over the subject ids and validate the corresponding form data
	foreach(array_column($subject_data,'id') as $key)
	{
		if($post['test_score'][$key] === '')
		{
			$error['test_score'][$key] = "Test Score Field is Required";
		}
		if($post['exam_score'][$key] === '')
		{
			$error['exam_score'][$key] = "Exam Score Field is Required";
		}
	}
	
	// if no errors, use the submitted data
	if(empty($error))
	{
		$sql = "INSERT INTO $table_name (
		subject_id,
		test_score,
		exam_score
		) VALUES (
		?,
		?,
		?
		)";
		$stmt = $pdo->prepare($sql);

		foreach(array_column($subject_data,'id') as $key)
		{
			$stmt->execute([
				$key,
				$post['test_score'][$key],
				$post['exam_score'][$key]
			]);
			
			// note: error handling for this query is not included with this example code
		}
	}
	
	// if no errors, success
	if(empty($error))
	{
		// if you want to display a one-time success message, store it in a session variable, then test, display, and clear that variable in the html document
		$_SESSION['success_message'] = 'You have successfully inserted the subject scores';
		// redirect to the exact same url of the current page to cause a get request - PRG Post, Redirect, Get.
		die(header("Refresh:0"));
	}
	
}

// get method business logic - get/produce data needed to display the page

// get all subject data - located above the post method form processing since it is also used by the validation logic


// html document
?>
<!DOCTYPE html>
<html lang="en-US">
	<head>
		<meta charset="utf-8">
		<title>Multi-row Insert Example</title>
	</head>
	<body>

<?php
// display and clear any success message
if(isset($_SESSION['success_message']))
{
	echo '<p>'.$_SESSION['success_message'].'</p>';;
	unset($_SESSION['success_message']);
}
?>

<?php
// display the form
?>
<form method="post">
<table class="table table-borderless">
<thead>
<tr>
<th>SN</th>
<th>Subject</th>
<th>Continuous Assessment Score</th>
<th>Examination Score</th>
</tr>
</thead>
<tbody>
<?php
$i = 1;
foreach($subject_data as $row)
{
	?>
	<tr>
	<th><?= $i++ ?></th>
	<td><input type="text" class="form-control border-0" readonly value="<?=$row['subject_name']?>"></td>
	<td><input type="number" name="test_score[<?=$row['id']?>]" class="form-control" value="<?=htmlentities($post['test_score'][$row['id']]??'',ENT_QUOTES)?>"><span style="color: red; font-size: .8em;"><?= $error['test_score'][$row['id']]??'' ?></span></td>
	<td><input type="number" name="exam_score[<?=$row['id']?>]" class="form-control" value="<?=htmlentities($post['exam_score'][$row['id']]??'',ENT_QUOTES)?>"><span style="color: red; font-size: .8em;"><?= $error['exam_score'][$row['id']]??'' ?></span></td>

	</tr>
	<?php
}
?>
<tr>
<td></td><td></td>
<td colspan="2"><button type="submit" class="btn btn-primary w-50">Save</button></td>
</tr>
</tbody>
</table>
</form>
</body>
</html>

this produces valid markup, validation per field, and repopulates the field values upon a validation error.

  • Like 1
Link to comment
Share on other sites

4 hours ago, mac_gyver said:

if you are not posting the actual code that you are having a problem with, the replies you get may not have anything to do with the problem.

here's example code (tested with faked data from the SELECT query) showing most of the points that i made -

<?php

// initialization

// recursive trim function
function _trim($val)
{
	if(is_array($val))
	{
		return array_map('_trim',$val);
	} else {
		return trim($val);
	}
}

session_start();

// make database connection here...

$table_name = 'your_table';

$error = []; // an array to hold user/validation errors
$post = []; // an array to hold a trimmed working copy of the form data

// get all subject data
$sql = "SELECT id, subject_name FROM tbl_subjects_secondary";
$stmt=$pdo->query($sql);
$subject_data = $stmt->fetchAll();


// post method form processing
if($_SERVER['REQUEST_METHOD'] === 'POST')
{
	// trim all the input data at once
	$post = _trim($_POST);
	
	// loop over the subject ids and validate the corresponding form data
	foreach(array_column($subject_data,'id') as $key)
	{
		if($post['test_score'][$key] === '')
		{
			$error['test_score'][$key] = "Test Score Field is Required";
		}
		if($post['exam_score'][$key] === '')
		{
			$error['exam_score'][$key] = "Exam Score Field is Required";
		}
	}
	
	// if no errors, use the submitted data
	if(empty($error))
	{
		$sql = "INSERT INTO $table_name (
		subject_id,
		test_score,
		exam_score
		) VALUES (
		?,
		?,
		?
		)";
		$stmt = $pdo->prepare($sql);

		foreach(array_column($subject_data,'id') as $key)
		{
			$stmt->execute([
				$key,
				$post['test_score'][$key],
				$post['exam_score'][$key]
			]);
			
			// note: error handling for this query is not included with this example code
		}
	}
	
	// if no errors, success
	if(empty($error))
	{
		// if you want to display a one-time success message, store it in a session variable, then test, display, and clear that variable in the html document
		$_SESSION['success_message'] = 'You have successfully inserted the subject scores';
		// redirect to the exact same url of the current page to cause a get request - PRG Post, Redirect, Get.
		die(header("Refresh:0"));
	}
	
}

// get method business logic - get/produce data needed to display the page

// get all subject data - located above the post method form processing since it is also used by the validation logic


// html document
?>
<!DOCTYPE html>
<html lang="en-US">
	<head>
		<meta charset="utf-8">
		<title>Multi-row Insert Example</title>
	</head>
	<body>

<?php
// display and clear any success message
if(isset($_SESSION['success_message']))
{
	echo '<p>'.$_SESSION['success_message'].'</p>';;
	unset($_SESSION['success_message']);
}
?>

<?php
// display the form
?>
<form method="post">
<table class="table table-borderless">
<thead>
<tr>
<th>SN</th>
<th>Subject</th>
<th>Continuous Assessment Score</th>
<th>Examination Score</th>
</tr>
</thead>
<tbody>
<?php
$i = 1;
foreach($subject_data as $row)
{
	?>
	<tr>
	<th><?= $i++ ?></th>
	<td><input type="text" class="form-control border-0" readonly value="<?=$row['subject_name']?>"></td>
	<td><input type="number" name="test_score[<?=$row['id']?>]" class="form-control" value="<?=htmlentities($post['test_score'][$row['id']]??'',ENT_QUOTES)?>"><span style="color: red; font-size: .8em;"><?= $error['test_score'][$row['id']]??'' ?></span></td>
	<td><input type="number" name="exam_score[<?=$row['id']?>]" class="form-control" value="<?=htmlentities($post['exam_score'][$row['id']]??'',ENT_QUOTES)?>"><span style="color: red; font-size: .8em;"><?= $error['exam_score'][$row['id']]??'' ?></span></td>

	</tr>
	<?php
}
?>
<tr>
<td></td><td></td>
<td colspan="2"><button type="submit" class="btn btn-primary w-50">Save</button></td>
</tr>
</tbody>
</table>
</form>
</body>
</html>

this produces valid markup, validation per field, and repopulates the field values upon a validation error.

Thank you so much. I will build on yours.

Link to comment
Share on other sites

45 minutes ago, I-AM-OBODO said:

Thank you so much. I will build on yours.

 

5 hours ago, mac_gyver said:

if you are not posting the actual code that you are having a problem with, the replies you get may not have anything to do with the problem.

here's example code (tested with faked data from the SELECT query) showing most of the points that i made -

<?php

// initialization

// recursive trim function
function _trim($val)
{
	if(is_array($val))
	{
		return array_map('_trim',$val);
	} else {
		return trim($val);
	}
}

session_start();

// make database connection here...

$table_name = 'your_table';

$error = []; // an array to hold user/validation errors
$post = []; // an array to hold a trimmed working copy of the form data

// get all subject data
$sql = "SELECT id, subject_name FROM tbl_subjects_secondary";
$stmt=$pdo->query($sql);
$subject_data = $stmt->fetchAll();


// post method form processing
if($_SERVER['REQUEST_METHOD'] === 'POST')
{
	// trim all the input data at once
	$post = _trim($_POST);
	
	// loop over the subject ids and validate the corresponding form data
	foreach(array_column($subject_data,'id') as $key)
	{
		if($post['test_score'][$key] === '')
		{
			$error['test_score'][$key] = "Test Score Field is Required";
		}
		if($post['exam_score'][$key] === '')
		{
			$error['exam_score'][$key] = "Exam Score Field is Required";
		}
	}
	
	// if no errors, use the submitted data
	if(empty($error))
	{
		$sql = "INSERT INTO $table_name (
		subject_id,
		test_score,
		exam_score
		) VALUES (
		?,
		?,
		?
		)";
		$stmt = $pdo->prepare($sql);

		foreach(array_column($subject_data,'id') as $key)
		{
			$stmt->execute([
				$key,
				$post['test_score'][$key],
				$post['exam_score'][$key]
			]);
			
			// note: error handling for this query is not included with this example code
		}
	}
	
	// if no errors, success
	if(empty($error))
	{
		// if you want to display a one-time success message, store it in a session variable, then test, display, and clear that variable in the html document
		$_SESSION['success_message'] = 'You have successfully inserted the subject scores';
		// redirect to the exact same url of the current page to cause a get request - PRG Post, Redirect, Get.
		die(header("Refresh:0"));
	}
	
}

// get method business logic - get/produce data needed to display the page

// get all subject data - located above the post method form processing since it is also used by the validation logic


// html document
?>
<!DOCTYPE html>
<html lang="en-US">
	<head>
		<meta charset="utf-8">
		<title>Multi-row Insert Example</title>
	</head>
	<body>

<?php
// display and clear any success message
if(isset($_SESSION['success_message']))
{
	echo '<p>'.$_SESSION['success_message'].'</p>';;
	unset($_SESSION['success_message']);
}
?>

<?php
// display the form
?>
<form method="post">
<table class="table table-borderless">
<thead>
<tr>
<th>SN</th>
<th>Subject</th>
<th>Continuous Assessment Score</th>
<th>Examination Score</th>
</tr>
</thead>
<tbody>
<?php
$i = 1;
foreach($subject_data as $row)
{
	?>
	<tr>
	<th><?= $i++ ?></th>
	<td><input type="text" class="form-control border-0" readonly value="<?=$row['subject_name']?>"></td>
	<td><input type="number" name="test_score[<?=$row['id']?>]" class="form-control" value="<?=htmlentities($post['test_score'][$row['id']]??'',ENT_QUOTES)?>"><span style="color: red; font-size: .8em;"><?= $error['test_score'][$row['id']]??'' ?></span></td>
	<td><input type="number" name="exam_score[<?=$row['id']?>]" class="form-control" value="<?=htmlentities($post['exam_score'][$row['id']]??'',ENT_QUOTES)?>"><span style="color: red; font-size: .8em;"><?= $error['exam_score'][$row['id']]??'' ?></span></td>

	</tr>
	<?php
}
?>
<tr>
<td></td><td></td>
<td colspan="2"><button type="submit" class="btn btn-primary w-50">Save</button></td>
</tr>
</tbody>
</table>
</form>
</body>
</html>

this produces valid markup, validation per field, and repopulates the field values upon a validation error.

I really learnt new stuffs from your list of to dos... and your code. thank you

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.