<?php
class Validator {
public $errors = array(
'password' => '',
'email' => '');
const PASSWORD_MINCHARS = 8;
public function checkEmail($email) {
if ($this->checkEmpty($email)) {
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
$this->errors['email'] = "Please provide a valid email";
return FALSE;
} else {
return TRUE;
}
} else {
$this->errors['email'] = "Please provide a value for the email";
return FALSE;
}
}
public function checkPassword($string) {
if ($this->checkEmpty($string)) {
if (strlen($string) < self::PASSWORD_MINCHARS) {
$this->errors['password'] = "The password should be atleast ".self::PASSWORD_MINCHARS." characters long.";
return FALSE;
} else {
return TRUE;
}
} else {
$this->errors['password'] = "Please provide a value for the password";
return FALSE;
}
}
private function checkEmpty($string) {
if (!empty($string)) {
return TRUE;
}
return FALSE;
}
public function displayErrors() {
$output = '';
foreach ($this->errors as $error) {
if (!empty($error)) {
$output .= '<p>'.$error.'</p>';
}
}
return $output;
}
}
?>
<?php
require 'Validator.php';
$validator = new Validator();
$email = '';
$password = '';
if ($validator->checkPassword($password) && $validator->checkEmail($email)) {
echo 'You have entered a valid password and email.';
} else {
echo $validator->displayErrors();
}
?>
The above code comes from two separate files. The one that comes begins with class Validator comes from Validator.php while the one that begins with the require function comes from index.php. So am just wondering why the method call that is $validator->displayErrors() in index.php only displays one error at a time instead of displaying them all at once.
There is only one error displayed because of your condition:
if ($validator->checkPassword($password) && $validator->checkEmail($email))
It executes your checkPassword method first, it returns false and so the second condition (which should execute the second validation method) is never checked.
You can avoid this by executing the validation methods first:
$validPassword = $validator->checkPassword($password);
$validEmail = $validator->checkEmail($email);
if ($validPassword && $validEmail) {
echo 'You have entered a valid password and email.';
} else {
echo $validator->displayErrors();
}
Replace
if ($validator->checkPassword($password) && $validator->checkEmail($email))
with
if ($validator->checkPassword($password) || $validator->checkEmail($email)) {
Related
I use OOP and i wanted to ask you guys how this would be done! I keep trying but its still not working ;(
Here is my class file:
class Signup {
// Error
public $error = array();
public function validate($username, $email_mobile, $password) {
if(!empty($username) || !empty($email_mobile) || !empty($password)){
if(strlen($username) < 3 || strlen($username) > 50){
$this->error = "Username is too short or too long!";
return $this->error;
}elseif(strlen($email_mobile) < 3 || strlen($email_mobile) > 50) {
$this->error = "Email is too short or too long!";
return $this->error;
}elseif(strlen($password) < 3 || strlen($password) > 50){
$this->error = "Password is too short or too long!";
return $this->error;
}
} else {
$this->error = "Please fill are required feilds";
return $this->error;
}
}
Here is my signup file
$error[] = $signup->validate($username, $email_mobile, $password);
<?php
// require('lib/function/signup.php');
if(isset($error)){
var_dump($error);
foreach ($error as $value) {
echo $value . "<br>";
}
}
?>
I know That im calling the $error in the same file and not the property error. But i dont know how to send this array to the other file! Please help me! Also i have Called everything and the problem is just with my code(i think), i only included my file and made a var to call my signup class
It is never too early in your development career to study coding standards. Jump straight to PSR-12, and adopt all of these guidelines to write beautiful, professional code.
Use data type declarations in your classes where possible, it will improve the data integrity throughout your project(s).
You appear to prefer returning an array of errors. For this reason, I see no benefit in caching the errors long-term in a class property. This coding style is fine to do, but you could choose to return nothing (void) and instead populate a class property $errors, then access it directly after the $signup->validate() call via $signup->errors or use a getter method.
The empty() checks are too late in the flow. Once the values have been passed to the class method, these values must already be declared. For this reason empty() is needless overhead to check for mere "falsiness". Just check the values' string length.
Your data quality checks seem a little immature (email and password checks should be much more complex), but I won't confuse you with any new complexity, but I do expect that your validation rules will increase as you realize that users cannot be trusted to put good values in forms without be forced to do so. For this reason, it is probably unwise to use a loop to check the value lengths because you will eventually need to write individual rules for certain values.
A possible write up:
class Signup
{
public function validate(
string $username,
string $email,
string $password
): array
{
$errors = [];
$usernameLength = strlen($username);
if ($usernameLength < 3 || $usernameLength > 50) {
$errors[] = "Username must be between 3 and 50 characters";
}
$emailLength = strlen($email);
if ($emailLength < 3 || $emailLength > 50) {
$errors[] = "Email must be between 3 and 50 characters";
}
$passwordLength = strlen($password);
if ($passwordLength < 3 || $passwordLength > 50) {
$errors[] = "Password must be between 3 and 50 characters";
}
return $errors;
}
}
When calling this method...
$signup = new Signup();
$errors = $signup->validate(
$_POST['username'] ?? '',
$_POST['email'] ?? '',
$_POST['password'] ?? ''
);
if ($errors) {
echo '<ul><li>' . implode('</li><li>', $errors) . '</li></ul>';
} else {
echo 'No errors';
}
You should add elements to the array, instead of overwriting it, and returning, on all the branches.
class Signup {
public $errors = [];
public function validate($username, $email_mobile, $password) {
if (empty($username)) {
$this->error[] = "Username cannot be empty";
} else {
$strlenUsername = strlen($username);
if ($strlenUsername < 3 || $strlenUsername > 50){
$this->errors[] = "Username is too short or too long!";
}
}
if (empty($email_mobile)) {
$this->error[] = "Email cannot be empty";
} else {
$strlenEM = strlen($email_mobile);
if ($strlenEM < 3 || $strlenEM > 50) {
$this->errors[] = "Email is too short or too long!";
}
}
if (empty($password)) {
$this->errors[] = "Password cannot be empty";
} else {
$strlenPass = strlen($password);
if ($strlenPass < 3 || $strlenPass > 50) {
$this->errors[] = "Password is too short or too long!";
}
}
return $this->errors;
}
}
If you always keep the same constrains for the three fields, you can shorten it:
class Signup {
public function validate($username, $email_mobile, $password) {
$errors = [];
$fields = [
'Username' => $username,
'Email' => $email_mobile,
'Password' => $password
];
foreach($fields as $key => $value) {
if (empty($value)) {
$errors[] = "$key cannot be empty";
} else {
$strlen = strlen($value);
if ($strlen < 3 || $strlen > 50) {
$errors[] = "$key is too short or too long!";
}
}
}
return $errors;
}
}
The above code guesses at what you are trying to do, if you just wanted a fix for not getting any results on $error see the original answer below.
Original answer.
Updating your code to this should give you the results you expect.
class Signup {
// Error
public $error = array();
public function validate($username, $email_mobile, $password) {
if (!empty($username) || !empty($email_mobile) || !empty($password)){
$strlenUsername = strlen($username);
$strlenEM = strlen($email_mobile);
$strlenPass = strlen($password);
if ($strlenUsername < 3 || $strlenUsername > 50){
$this->error[] = "Username is too short or too long!";
} elseif ($strlenEM < 3 || $strlenEM > 50) {
$this->error[] = "Email is too short or too long!";
} elseif ($strlenPass < 3 || $strlenPass > 50){
$this->error[] = "Password is too short or too long!";
}
} else {
$this->error[] = "Please fill are required feilds";
}
return $this->error;
}
}
Keep in mind that, since you are using if-else you will always have, at most, one element in the array, it is hard to tell what you are trying to do with certainty, so I didn't change the logic and just fixed the most obvious problem.
If you want to add error messages to the array, get rid of the else keyword on the conditionals.
If you want to only receive one error message, consider using a string instead of an array.
I have this validation code:
public function validate() {
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
foreach ($this->required as $field) {
if (empty($_POST[$field])) {
$this->error = $this->message['required'];
}
}
if (!ctype_alnum($_POST['text'])) {
$this->error = $this->message['text']['alphanum'];
}
if (strlen($_POST['text']) > 3) {
$this->error = $this->message['text']['length'];
}
}
return $this->error;
}
The problem is that even if the 'text' input is empty, it skips the if (empty($_POST[$field])) statement and goes to the if (!ctype_alnum($_POST['text'])) statement instead, displaying its error.
If I comment out the if (!ctype_alnum($_POST['text'])) statement, then it works properly and displays the "This field is required" error if the 'text' input is empty on submission.
It also works if I get the statement out of the foreach loop and use elseif, like this:
if (empty($_POST['text'])) {
$this->error = $this->message['required'];
} elseif (!ctype_alnum($_POST['text'])) {
$this->error = $this->message['text']['alphanum'];
}
But I'd like to use the loop and not use elseif, especially because I'll have a lot of required fields to validate.
I also tried:
Removing the if (empty($_POST[$field])) statement from the loop and adding it as the other ones: if (empty($_POST['text']));
Using $_POST['text'] == '' instead of empty();
Using strlen($_POST['text']) == 0 instead of empty();
Using preg_match() instead of ctype_alnum.
This shows when I use var_dump($_POST['text']) and submitting with an empty input:
/home/vagrant/code/test/index.php:13:string '' (length=0)
I can't figure out why and how to make it not skip the empty validation when using ctype_alnum() or preg_match().
The problem is you are overwriting $this->error if following conditions hold true, i.e. you won't get a $this->message['required'] back if the next condition, !ctype_alnum($_POST['text']) is true and overwrites $this->error with its message.
So you need to return $this->message inside each condition.
public function validate() {
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
foreach ($this->required as $field) {
if (empty($_POST[$field])) {
$this->error = $this->message['required'];
return $this->error;
}
}
if (!empty($_POST['text']) {
if (!ctype_alnum($_POST['text'])) {
$this->error = $this->message['text']['alphanum'];
return $this->error;
}
if (strlen($_POST['text']) > 3) {
$this->error = $this->message['text']['length'];
return $this->error;
}
}
}
return $this->error;
}
I'd suggest just checking if the 'text' field is empty before checking any other criteria on it like this:
public function validate() {
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
foreach ($this->required as $field) {
if (empty($_POST[$field])) {
$this->error = $this->message['required'];
}
}
if (!empty($_POST['text']) {
if (!ctype_alnum($_POST['text'])) {
$this->error = $this->message['text']['alphanum'];
}
if (strlen($_POST['text']) > 3) {
$this->error = $this->message['text']['length'];
}
}
}
return $this->error;
}
I have a form in which I am using a preg_match function to validate fields. I have a generalized function for the matching. The function validateForm() is being called earlier on in the script with the appropriate values.
When the function is NOT passed any values, all the fields show the error message despite having correctly matching information. Generalized function with no arguments:
function validateForm() {
if(preg_match()) {
return true;
}
else {
return false;
}
} // end function validateForm
When I pass just ONE specific regex/field pair argument, all the fields begin to validate and show the error message when appropriate (so basically the code works as it should despite having a field-specific argument in the function). For example, when I pass this single regex/field argument into preg_match, all the fields begin to validate each field correctly, regardless of the fact that I am only checking for the 'City' field in this case. Example of passing a field-specific argument, in which all the code 'works':
function validateForm($cityRegex, $city) {
if(preg_match($cityRegex, $city)) {
return true;
}
else {
return false;
}
} // end function validateForm
Can someone explain to me why, when passed a specific argument for a specific field, the function will work for all individual preg_match arguments in the code? The script is running as I would want it to, I just do not understand why the specific argument is what makes it validate all fields.
Here is all of the PHP code, if needed:
<?php
$first = '';
$last = '';
$phone = '';
$city = '';
$state = '';
$error_message = '';
$firstLastRegex = '/^[a-zA-Z]{2,15}$/';
$lastRegex = '/^[a-zA-Z]{2,15}$/';
$phoneRegex = '/^(\(\d{3}\))(\d{3}\-)(\d{4})$/';
$cityRegex = '/^[a-zA-Z]{3,20}$/';
$stateRegex = '/^[a-zA-Z]{2}$/';
$validate_first = '';
$validate_last = '';
$validate_phone = '';
$validate_city = '';
$validate_state = '';
$phone_string = '';
if(isset($_POST['submit'])) {
$first = $_POST['firstName'];
$last = $_POST['lastName'];
$phone = $_POST['phoneNumber'];
$city = $_POST['userCity'];
$state = $_POST['userState'];
$show_form = false;
$phone_string = str_replace(array('-', '(', ')'), '', $phone);
$validate_first = validateForm($firstLastRegex, $first);
$validate_last = validateForm($lastRegex, $last);
$validate_phone = validateForm($phoneRegex, $phone);
$validate_city = validateForm($cityRegex, $city);
$validate_state = validateForm($stateRegex, $state);
if($validate_first == false) {
$show_form = true;
$error_message .= "Please enter your FIRST name between 2 and 15 letters.<br>";
}
if($validate_last == false) {
$show_form = true;
$error_message .= "Please enter your LAST name between 2 and 15 letters.<br>";
}
if($validate_phone == false) {
$show_form = true;
$error_message .= "Please enter your phone number in (###)###-### format.<br>";
}
if($validate_city == false) {
$show_form = true;
$error_message .= "Please enter your city name between 3 and 20 letters.<br>";
}
if($validate_state == false) {
$show_form = true;
$error_message .= "Please enter your state's abbreviation (Example: CA).<br>";
}
} // end if isset();
else {
$show_form = true;
$error_message = "";
} // end else
// REGEX FUNCTION
function validateForm() {
if(preg_match()) {
return true;
}
else {
return false;
}
} // end function validateForm
?>
You still need to have arguments for you function. The code below will make your validate function work.
function validateForm($regEx, $field) {
if(preg_match($regEx, $field)) {
return true;
}
else {
return false;
}
} // end function validateForm
I also see other potential issues with not checking if post variables are set before using them, and you are setting $show_form = true for all your if/else cases. I'm sure you can figure everything else out with some debug statements.
I am trying this code as part of form processing:
<?php
if(isset($_POST['senderEmail']))
{
try
{
require '_php/_security/validation.php'; //SEE BELOW
$rules = array(
'senderEmail' => 'validEmail',
'emailTextbox' => 'validTextbox',
);
$validation = new Validation();
if ($validation->validate($_POST, $rules) == TRUE) {
require("_php/database/dbProcessing.php"); //Form Proccessing for database inclusion
}
else {
foreach($validation->emailErrors as $error){
$emailErrors[] = $error;
$_SESSION['$emailErrors'] = $emailErrors;
header('Location:indexmobile.php#emailErrors');
die('ABORT!');
}
}
}
catch (PDOException $e)
{
$error = 'Error adding elements to database: ' . $e->getMessage();
echo "Error: " . $error;
exit();
}
exit();
}
?>
The validation.php where I do my validation has this:
<?php
class Validation {
public $errors = array();
public function validate($data, $rules) {
$valid = TRUE;
foreach ($rules as $fieldname => $rule) {
$callbacks = explode('|', $rule);
foreach ($callbacks as $callback) {
$value = isset($data[$fieldname]) ? $data[$fieldname] : NULL;
if ($this->$callback($value, $fieldname) == FALSE) $valid = FALSE;
}
}
return $valid;
}
public function validEmail($value, $fieldname) {
$valid = !empty($value);
if ($valid == FALSE) {
$this->emailErrors[] = "The $fieldname is required";
return $valid;
} else {
$valid = filter_var($value, FILTER_VALIDATE_EMAIL);
if ($valid == FALSE) $this->emailErrors[] = "The $fieldname needs to be a valid email";
return $valid;
}
}
public function validTextbox($value, $fieldname) {
$valid = !empty($value);
if ($valid == FALSE) {
$this->emailErrors[] = "The $fieldname is required";
return $valid;
} else {
$whitelist = '/^[a-zA-Z0-9 ,\.\+\\n;:!_\-#]+$/';
$textarea = strip_tags($value);
$textarea = mysql_real_escape_string($textarea);
$valid = preg_match($whitelist, $textarea);
if ($valid == FALSE) $this->errors[] = "The $fieldname contains invalid characters";
return $valid;
}
}
}
Upon using this, Im have issues with the redirect (I think). It seems further that Im having errors in validation. My questions are thus:
Am I doing the header redirect correctly? I've read that " header() must be called before any actual output is sent,.." So is this the reason why this redirect is incorrect? how to make a redirect if i need to show/send something to the redirected page?
function validTextbox always ends up an error that the field is empty. Why so?
Is my entire process of form validation a good way of validating form fields (which i learned from watching an online tutorial)? What is a better way?
Is there something wrong with error reporting in this case?
Thank you for those who replies. I am new to PHP and trying my best to learn the language.
1 - There are several ways to pass on a message to the page you are redirecting to. One is through $_GET like this
$message="Some message for the next page.";
$message=urlencode($message);
header("Location:page.php?message=".$message);
then on page.php
if(!empty($_GET['message']))
{
$_GET['message'];
}
similarly you can also use the session (less secure)
$_SESSION['message']='some other message';
then on page.php
if (!empty($_SESSION['message']))
{
echo $_SESSION['message'];
unset($_SESSION['message']);
}
2 - I would have to see what you are passing to your validate function. You should do a var_dump of $_POST and add that to your question.
3 - It depends on your criteria. If you are just checking for emptiness its overkill. I don't know what text you need / consider valid, but a regex is a reasonable way of enforcing validation.
4 - See #2.
I am using jQuery Form Validation Plugin to do comprehensive client side validation.
Now I would like to use PHP to do the server side validation.
Check whether the email is email, age is in the right range, etc.
Is there similar package or function collections that I can use rather than write all validation method manually?
Thank you
If you're writing more or less complex application, you probably would benefit from using a framework, such as Zend Framework for instance. It has some standalone classes to aid validation process as well, for example Zend_Validate: http://framework.zend.com/manual/en/zend.validate.html
The closest thing that's bundled with PHP is the filter extension. It does validation and sanitization.
for email validation you can use is_email function.
Check the link:http://www.ohloh.net/p/isemail
These are a couple of methods I use
<?php
function chkReq($fields) {
foreach($fields as $name) {
if(req($name)) {
global $values;
$values[$name] = $_POST[$name];
} else {
global $errors;
$errors[$name] = "This field is required";
}
}
}
function req($name) {
if(isset($_POST[$name]) && !empty($_POST[$name])) {
return true;
} else {
return false;
}
}
function chkDate($name, $from, $to) {
global $errors;
global $values;
if(!req($name)) {
$errors[$name] = "This field is required";
} elseif(!betweenNumbers($_POST[$name], $from, $to)) {
$errors[$name] = "Value must be between $from en $to .";
$values[$name] = $_POST[$name];
} else {
$values[$name] = $_POST[$name];
}
}
function betweenNumbers($value, $from, $to) {
if($value >= $from && $value <= $to) {
return true;
} else {
return false;
}
}
function chk3Fields($field1, $field2, $field3) {
global $errors;
global $values;
if(!req($field1) && !req($field2) && !req($field3)) {
$errors[$field1] = "One of the three fields is required";
$errors[$field2] = "One of the three fields is required";
$errors[$field3] = "One of the three fields is required";
} else {
$values[$field1] = $_POST[$field1];
$values[$field2] = $_POST[$field2];
$values[$field3] = $_POST[$field3];
}
}
function checkRegistry($name){
global $errors;
global $values;
if(!req($name)) {
$errors[$name] = "This field is mandatory";
} elseif(!validRegistry($_POST[$name])) {
$errors[$name] = "This is not a valid registry number";
$values[$name] = $_POST[$name];
} else {
$values[$name] = $_POST[$name];
}
}
function validRegistry($value) {
$value = preg_replace("/(\.|-)/", "", $value);
$firstPart= substr($value, 0,9);
$residueFirstPart= $firstPart% 97;
$calculatedControlNr = 97 - $residueFirstPart;
$obzervedControlNr = substr($value, 9, 2);
return ($calculatedControlNr == $obzervedControlNr);
}
?>