Form Validation with PHP -- Goto?

Hello there,

I am working on a fairly large project and figuring out how to approach the form validation with PHP. Stripped down to its bare essentials, it basically looks like this:

===

<?php

$fruit = array(
	array('id' => '1', 'name' => 'apple'),
	array('id' => '2', 'name' => 'pear'),
	array('id' => '3', 'name' => 'plum'),
	array('id' => '4', 'name' => 'strawberry'),
	array('id' => '5', 'name' => 'gooseberry'),
	array('id' => '6', 'name' => 'currant')
	);

session_start();


if (isset($_GET['startover'])) {
	
	if (isset($_SESSION['favoriteNumber'])) {
		unset($_SESSION['favoriteNumber']);
	}
	if (isset($_SESSION['favoriteFruit'])) {
		unset($_SESSION['favoriteFruit']);
	}
	header('Location: .');
	exit();
}


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

	include 'confirmation.html.php';
	exit();
}


if (isset($_POST['goToPreview'])) {
	
	$favoriteFruitKeys = $_POST['favoriteFruitKeys'];
	
	foreach ($favoriteFruitKeys as $id):
		foreach ($fruit as $item):	
		if ($item['id'] == $id) {
		$favoriteFruit[] = array(
				'id' => $item['id'],
				'name' => $item['name']
				);
		}
		endforeach;
	endforeach;
	
	$_SESSION['favoriteFruit'] = $favoriteFruit;	
	include 'preview.html.php';
	exit();
}


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

	$favoriteNumber = $_POST['favoriteNumber'];
	$_SESSION['favoriteNumber'] = $favoriteNumber;
	include 'input2.html.php';
	exit();

}


if (empty($_GET)) {


	include 'input1.html.php';
	exit();
}


include 'error.html.php';

===

The tricky part is that I would like to keep each of those large “if” blocks intact: in the actual project, they contain a bunch of shuttling of material back and forth to a database. I came up with a solution that does what I want, but requires the “goto” statement.

===

<?php

$fruit = array(
	array('id' => '1', 'name' => 'apple'),
	array('id' => '2', 'name' => 'pear'),
	array('id' => '3', 'name' => 'plum'),
	array('id' => '4', 'name' => 'strawberry'),
	array('id' => '5', 'name' => 'gooseberry'),
	array('id' => '6', 'name' => 'currant')
	);

session_start();


if (isset($_GET['startover'])) {
	
	if (isset($_SESSION['favoriteNumber'])) {
		unset($_SESSION['favoriteNumber']);
	}
	if (isset($_SESSION['favoriteFruit'])) {
		unset($_SESSION['favoriteFruit']);
	}
	header('Location: .');
	exit();
}


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

	include 'confirmation.html.php';
	exit();
}


if (isset($_POST['goToPreview'])) {
	
	if (isset($_POST['goToPreview']) and ($_POST['goToPreview'] == 'Clear')) {
		$_POST['favoriteNumber'] = $_SESSION['favoriteNumber'];
		goto validationInput2;
	}
	
	if (!empty($_POST['favoriteFruitKeys'])) {
		$favoriteFruitKeys = $_POST['favoriteFruitKeys'];
		
		foreach ($favoriteFruitKeys as $id):
			foreach ($fruit as $item):	
			if ($item['id'] == $id) {
			$favoriteFruit[] = array(
					'id' => $item['id'],
					'name' => $item['name']
					);
			}
			endforeach;
		endforeach;
		
		$_SESSION['favoriteFruit'] = $favoriteFruit;	
	
	} else {
	
		$_POST['favoriteNumber'] = $_SESSION['favoriteNumber'];
		$favoriteFruitKeys = 0;
		goto validationInput2;	
	}
	
		include 'preview.html.php';
		exit();
}


if (isset($_POST['goToInput2'])) {
	
	validationInput2:
	if ((isset($favoriteFruitKeys)) and ($favoriteFruitKeys == 0)) {
		$notValidFruit = 'Please select at least one item.';
	}
	
	if (isset($_POST['goToInput2']) and ($_POST['goToInput2'] == 'Clear')) {
		if (isset($_SESSION['favoriteNumber'])) {
		unset($_SESSION['favoriteNumber']);
		}
		goto validationInput1;
	}

	if (!empty($_POST['favoriteNumber'])) {
		$favoriteNumber = $_POST['favoriteNumber'];
		$_SESSION['favoriteNumber'] = $favoriteNumber;
	
	} else {
	
		$favoriteNumber = 0;
		goto validationInput1;
	}

	include 'input2.html.php';
	exit();
}


if (empty($_GET)) {

	validationInput1:
	if ((isset($favoriteNumber)) and ($favoriteNumber == 0)) {
		$notValidNumber = 'Please select a number.';
	}

	include 'input1.html.php';
	exit();
}


include 'error.html.php';

===

It is not an elegant approach, but it works. However, I have read so much controversial material about “goto” that I am wondering if it will lead to problems down the road. Or perhaps there is another approach that I didn’t think of.

The only alternative that came to mind for me was to actually split the code blocks into separated PHP files and then jump around as needed with <form action=“input2.php” method=“post”> and so forth. And then if I need to go someplace else for validation, just use a header(‘Location:’) redirect of some sort.

That doesn’t seem too sleek either, but perhaps it is the most appropriate solution in this case.

Thoughts? Comments? Suggestions?

Any feedback would be greatly appreciated.
Many thanks.

P.S. Btw, the relevant HTML is here:

<h1>Input 1</h1>

<p>Pick your favorite number.</p>

<form action="" method="post">
	<fieldset>
	<legend>Numbers</legend>
	<div class="notvalid"><?php if (isset($notValidNumber)) echo $notValidNumber; ?></div>
	<ul>
		<li><input type="radio" name="favoriteNumber" value="1" id="number1" />
		<label for="number1">1</label></li>
		<li><input type="radio" name="favoriteNumber" value="2" id="number2" />
		<label for="number2">2</label></li>
		<li><input type="radio" name="favoriteNumber" value="5" id="number5" />
		<label for="number5">5</label></li>
	</ul>
	</fieldset>
	<input type="submit" name="goToInput2" value="Clear" />
	<input type="submit" name="goToInput2" value="Next" />
</form>
<h1>Input 2</h1>

<p>Pick your favorite fruit.</p>
<p>Check all that apply.</p>

<form action="" method="post">
	<fieldset>
	<legend>Fruit</legend>
	<div class="notvalid"><?php if (isset($notValidFruit)) echo $notValidFruit; ?></div>
	<ul>
	<?php foreach ($fruit as $item): ?>
		<li>
		<input type="checkbox" name="favoriteFruitKeys[]" id="fruit<?php echo $item['id'];?>" value="<?php echo $item['id']; ?>" />
		<label for="fruit<?php echo $item['id'];?>"><?php echo $item['name'];?></label>
		</li>
	<?php endforeach; ?>
	</ul>
	</fieldset>
	<input type="submit" name="goToPreview" value="Clear" />
	<input type="submit" name="goToPreview" value="Next" />
</form>
<h1>Preview</h1>

<p>Please proofread your selection.</p>

<form action="" method="post">
	<fieldset>
	<legend>Favorite Number</legend>
	<?php echo $_SESSION['favoriteNumber'];?>
	</fieldset>
	<fieldset>
	<legend>Favorite Fruit</legend>
	<ul>
	<?php foreach ($favoriteFruit as $item):?>
	<li>
	<?php echo $item['name'];?>
	</li>
	<?php endforeach;?>
	</ul>
	</fieldset>
	<input type="submit" name="submitSelection" value="Submit" />
</form>
<h1>Confirmation</h1>

<p>Congratulations! Your selection has been added to our pretend database!</p>

<p><a href="?startover">Enter another</a>.</p>

I would tend to think in terms of functions. Probably each of your blocks (the ones you “goto”) is a function. So maybe instead of

goto validationInput1;

you call a function

validateInput1();

See if that line of thinking works for what you’re after.

Hello Robert,

Thank you so much for your input.

I agree that functions would be a better way to handle the validation. What I don’t grasp is this: say the input goes through the validation function and fails – how do I then make the browser redirect to the page the input came from rather than the next page?

It’s almost like I’m looking for a header(‘Location: .$_POST[‘whatever’]’); but I don’t know the proper syntax to express it.

Actually, now that I’ve turned it over in my mind a little bit, I think I kind of see what you’re getting at. Let me work on this a little more, and maybe I can get it to function – pun intended :wink:

Okay, I’ve rewired my code to pull up the chunks through functions. I also initially did some validation for the first page.

<?php

$fruit = array(
	array('id' => '1', 'name' => 'apple'),
	array('id' => '2', 'name' => 'pear'),
	array('id' => '3', 'name' => 'plum'),
	array('id' => '4', 'name' => 'strawberry'),
	array('id' => '5', 'name' => 'gooseberry'),
	array('id' => '6', 'name' => 'currant')
	);


function startOver() {
	if (isset($_SESSION['favoriteNumber'])) {
		unset($_SESSION['favoriteNumber']);
	}
	if (isset($_SESSION['favoriteFruit'])) {
		unset($_SESSION['favoriteFruit']);
	}
	header('Location: .');
	exit();
	return;
}


function goToConfirmation() {
	include 'confirmation.html.php';
	exit();
	return;
}	
	
function goToPreview() {
	global $fruit;
	$favoriteFruitKeys = $_POST['favoriteFruitKeys'];
		
		foreach ($favoriteFruitKeys as $id):
			foreach ($fruit as $item):	
			if ($item['id'] == $id) {
			$favoriteFruit[] = array(
					'id' => $item['id'],
					'name' => $item['name']
					);
			}
			endforeach;
		endforeach;
		
	$_SESSION['favoriteFruit'] = $favoriteFruit;
	include 'preview.html.php';
	exit();
	return;
}
	
function goToInput2() {
	global $fruit;
	include 'input2.html.php';
	exit();
	return;
}
	
function goToInput1($arg) {
	$notValidNumber = $arg;
	include 'input1.html.php';
	exit();
	return;
}

function validateInput1() {
	goToInput1('Please select a number.');
	exit();
}


session_start();


if (isset($_GET['startover'])) {	
	startOver();
}


if (isset($_POST['submitSelection'])) {
	goToConfirmation();
}


if (isset($_POST['goToPreview'])) {	
	goToPreview();
}


if (isset($_POST['goToInput2'])) {
	
	if (!empty($_POST['favoriteNumber'])) {
		$favoriteNumber = $_POST['favoriteNumber'];
		$_SESSION['favoriteNumber'] = $favoriteNumber;
		goToInput2();
	
	} else {
		validateInput1();
		exit();
	}
}


if (empty($_GET)) {
	$notValidNumber = '';
	goToInput1($notValidNumber);	
}


include 'error.html.php';

This approach is a little unfamiliar to me… does it look like I am on the right track?

Well, here is what I came up with in the end, in terms of validation…

<?php

$fruit = array(
	array('id' => '1', 'name' => 'apple'),
	array('id' => '2', 'name' => 'pear'),
	array('id' => '3', 'name' => 'plum'),
	array('id' => '4', 'name' => 'strawberry'),
	array('id' => '5', 'name' => 'gooseberry'),
	array('id' => '6', 'name' => 'currant')
	);


function startOver() {
	if (isset($_SESSION['favoriteNumber'])) {
		unset($_SESSION['favoriteNumber']);
	}
	if (isset($_SESSION['favoriteFruit'])) {
		unset($_SESSION['favoriteFruit']);
	}
	header('Location: .');
	exit();
	return;
}


function goToConfirmation() {
	include 'confirmation.html.php';
	exit();
	return;
}	
	
function goToPreview() {
	global $fruit;
	$favoriteFruitKeys = $_POST['favoriteFruitKeys'];
		
		foreach ($favoriteFruitKeys as $id):
			foreach ($fruit as $item):	
			if ($item['id'] == $id) {
			$favoriteFruit[] = array(
					'id' => $item['id'],
					'name' => $item['name']
					);
			}
			endforeach;
		endforeach;
		
	$_SESSION['favoriteFruit'] = $favoriteFruit;
	include 'preview.html.php';
	exit();
	return;
}
	
function goToInput2($beta) {
	$notValidFruit = $beta;
	
	if (isset($_POST['favoriteNumber'])) {
		$favoriteNumber = $_POST['favoriteNumber'];
		$_SESSION['favoriteNumber'] = $favoriteNumber;
	}
	global $fruit;
	include 'input2.html.php';
	exit();
	return;
}
	
function goToInput1($beta) {
	$notValidNumber = $beta;
	
	include 'input1.html.php';
	exit();
	return;
}

function validateInput2() {
	goToInput2('Please select at least one item.');
	exit();
}

function validateInput1() {
	goToInput1('Please select a number.');
	exit();
}


session_start();


if (isset($_GET['startover'])) {	
	startOver();
}


if (isset($_POST['submitSelection'])) {
	goToConfirmation();
}


if (isset($_POST['goToPreview'])) {	
	
	if (!empty($_POST['favoriteFruitKeys'])) {
		goToPreview();
		
	} else {
		validateInput2();
		exit();
	}
}


if (isset($_POST['goToInput2'])) {
	
	if (!empty($_POST['favoriteNumber'])) {
		goToInput2('');
	
	} else {
		validateInput1();
		exit();
	}
}


if (empty($_GET)) {
	goToInput1('');	
}


include 'error.html.php';