Fix #4639
Really fix #4633
diff --git a/system/libraries/Form_validation.php b/system/libraries/Form_validation.php
index f5b07a2..04445f5 100644
--- a/system/libraries/Form_validation.php
+++ b/system/libraries/Form_validation.php
@@ -696,6 +696,17 @@
 				$param = $match[2];
 			}
 
+			// Ignore empty, non-required inputs with a few exceptions ...
+			if (
+				($postdata === NULL OR $postdata === '')
+				&& $callback === FALSE
+				&& $callable === FALSE
+				&& ! in_array($rule, array('required', 'isset', 'matches'), TRUE)
+			)
+			{
+				continue;
+			}
+
 			// Call the function that corresponds to the rule
 			if ($callback OR $callable !== FALSE)
 			{
diff --git a/tests/codeigniter/libraries/Form_validation_test.php b/tests/codeigniter/libraries/Form_validation_test.php
index d11d616..b87ca65 100644
--- a/tests/codeigniter/libraries/Form_validation_test.php
+++ b/tests/codeigniter/libraries/Form_validation_test.php
@@ -40,11 +40,22 @@
 
 	public function test_rule_required()
 	{
-		$rules = array(array('field' => 'foo', 'label' => 'foo_label', 'rules' => 'required'));
-		$this->assertTrue($this->run_rules($rules, array('foo' => 'bar')));
+		$rules = array(array('field' => 'foo', 'label' => 'Foo', 'rules' => 'is_numeric'));
 
+		// Empty, not required
+		$this->assertTrue($this->run_rules($rules, array('foo' => '')));
+
+
+		// Not required, but also not empty
+		$this->assertTrue($this->run_rules($rules, array('foo' => '123')));
+		$this->assertFalse($this->run_rules($rules, array('foo' => 'bar')));
+
+		// Required variations
+		$rules[0]['rules'] .= '|required';
+		$this->assertTrue($this->run_rules($rules, array('foo' => '123')));
 		$this->assertFalse($this->run_rules($rules, array('foo' => '')));
 		$this->assertFalse($this->run_rules($rules, array('foo' => ' ')));
+		$this->assertFalse($this->run_rules($rules, array('foo' => 'bar')));
 	}
 
 	public function test_rule_matches()