Php Form Validation Class displaying errors - php

I have the following php form Validation class, which allows me to specify which form inputs are required, the length, and whether the input should be unique.
<?php
class Validate {
private $_passed = false,
$_errors = array(),
$_db = null;
public function __construct() {
$this->_db = DB::getInstance();
}
public function check($source, $items = array()) {
foreach($items as $item => $rules) {
foreach($rules as $rule => $rule_value) {
$value = trim($source[$item]);
if($rule === 'required' && empty($value)) {
$this->addError("{$item} is required.");
} else if (!empty($value)) {
switch($rule) {
case 'min':
if(strlen($value) < $rule_value) {
$this->addError("{$item} must be a minimum of {$rule_value} characters.");
}
break;
case 'max':
if(strlen($value) > $rule_value) {
$this->addError("{$item} must be a maximum of {$rule_value} characters.");
}
break;
case 'matches':
if($value != $source[$rule_value]) {
$this->addError("{$rule_value} must match {$item}.");
}
break;
case 'unique':
$check = $this->_db->get('users', array($item, '=', $value));
if($check->count()) {
$this->addError("{$item} is already taken.");
}
break;
}
}
}
}
if(empty($this->_errors)) {
$this->_passed = true;
}
return $this;
}
protected function addError($error) {
$this->_errors[] = $error;
}
public function passed() {
return $this->_passed;
}
public function errors() {
return $this->_errors;
}
}
My question is, at the moment the class returns an array of errors which I'm able to foreach through:
foreach($validate->errors() as $error) {
echo $error;
}
but I'm wondering what I can do to allow me to show the errors individually - so I could show the relevant error under the relevant field on the form - as opposed to all as a block at the top.
I hope I've been able to explain that ok!!!

You could try to add some kind of key to the errors array, something like this:
protected function addError($key, $error) {
$this->_errors[$key] = $error;
}
And on every call to addError function (I think you can use $rule as key, but if not then you should add one different key for every field, for example id of the html elements or name...):
$this->addError($item, "{$item} is already taken.");
It's just an idea... let me know if it's not clear
EDITED: Changed $rule as key for $item

Related

How to redefine variable value and use value to other method in class PHP?

I can't get value variable in a method, after use this value to another method in one class PHP Laravel.
public function paymentCourse(Request $request)
{
$idCourse = $request->input('idcourse');
$CoursePrice = Course::where('id', $idCourse)->first();
if(Auth::user()->palate) {
if(Auth::user()->palate->is_palate == 1) {
// this value I want to transfer method getTransactionAmount()
$currentPrice = $CoursePrice->price_palate;
}
} else {
// this value I want to transfer method getTransactionAmount()
$currentPrice = $CoursePrice->price;
}
return view('pages.payment-course', compact('currentPrice'));
}
public function getTransactionAmount($type) {
switch ($type) {
case 'palate':
return 11645;
break;
case 'course':
return 15000; // I get value method paymentCourse() $currentPrice.
break;
case 'course_sale':
return 12000; // I get value method paymentCourse() $currentPrice.
break;
default:
throw new \Exception('Wrong transaction type');
}
}
This is my solution, thank you for help.
public function paymentCourse(Request $request)
{
$idCourse = $request->input('idcourse');
$CoursePrice = Course::where('id', $idCourse)->first();
if(Auth::user()->palate) {
if(Auth::user()->palate->is_palate == 1) {
$currentPrice = $CoursePrice->price_palate;
\Session::put('currentPrice', $currentPrice);
}
} else {
$currentPrice = $CoursePrice->price;
\Session::put('currentPrice', $currentPrice);
}
return view('pages.payment-course', compact('currentPrice'));
}
private function getTransactionAmount($type) {
$currentPrice = \Session::get('currentPrice');
switch ($type) {
case 'palate':
return 11645;
break;
case 'course':
return $currentPrice;
break;
case 'course_sale':
return $currentPrice;
break;
default:
throw new \Exception('Wrong transaction type');
}
}

When should I return?

I am struggling to create an access object to sections stored in the Database. This is a skellington of the process, this contains static data until I can get the principle working.
class User {
const IS_ADMIN = 1;
const IS_MODERATOR = 2;
const IS_MEMBER = 4;
}
This class will auto-load data from the database eventually but for the time being, this class has default values.
class Scope {
private $priv = [];
public function __construct() {
$this->priv = [1];
}
public function getPrivilidges() {
return $this->priv;
}
}
This is where it messes up, I can tell that the second and third conditions cannot be met if the first fails, how can I stop this?
class Priverlidges {
public function canView($type, Scope $scope) {
if($type & User::IS_ADMIN) {
foreach($scope->getPrivilidges() as $p) {
if($p == User::IS_ADMIN) continue;
return false;
}
return true;
}
if($type & User::IS_MODERATOR) {
foreach($scope->getPrivilidges() as $p) {
if($p == User::IS_MODERATOR) continue;
return false;
}
return true;
}
if($type & User::IS_MEMBER) {
foreach($scope->getPrivilidges() as $p) {
if($p == User::IS_MEMBER) continue;
return false;
}
return true;
}
}
}
Example usage which works fine when the default value of the priverlidge is 1:
echo (int)(new Priverlidges)->canView(User::IS_ADMIN, new Scope());
Example usage which works fine when the default value of the priverlidge is 2:
echo (int)(new Priverlidges)->canView(User::IS_MODERATOR | User::IS_ADMIN, new Scope()); // it returns false at the first condition
Can anyone help me with when to return true or false? Thanks in advance.
P.S - Users can be both Mods and Admins
EDIT: I have tried to use in_array() and still am unsure when to return the value true or false because it get's overwrite if the second method runs.
I figured it out. First, check the user is not already authenticated using a placeholder ($this->_state). Then check the type of user and check it is inside the scope.
class Priverlidges {
private $_state = false;
public function canView($type, Scope $scope) {
if(!$this->_state && $type & User::IS_ADMIN && in_array(User::IS_ADMIN, $scope->getPrivilidges())) {
$this->_state = true;
}
if(!$this->_state && $type & User::IS_MODERATOR && in_array(User::IS_MODERATOR, $scope->getPrivilidges())) {
$this->_state = true;
}
if(!$this->_state && $type & User::IS_MEMBER && in_array($scope->getPrivilidges(), User::IS_MEMBER)) {
$this->_state = true;
}
return $this->_state;
}
}

Call to a member function count() on a non-object, Line 23

Having trouble understanding why I can't count() the $check variable in my code. The code is suppose to be checking to see if the sql has returned any values.
Please let me know if I need to submit anymore information.
<?php
class Validate {
private $_passed = false,
$_errors = array(),
$_db = null;
public function __construct() {
$this->_db = DB::getInstance();
}
public function check($source, $items = array()) {
foreach($items as $item => $rules) {
foreach($rules as $rule => $rule_value) {
$value = $source[$item];
if($rule === 'required' && empty($value)) {
$this->addError("{$item} is required");
} else if(!empty($value)){
switch($rule) {
case 'matches':
if($value!=$source[$rule_value]) {
$this->addError("{$rule_value} must match {$item}");
}
break;
case 'unique':
$check = $this->_db->get($rule_value, array($item, '=', $value));
if ($check->count()) {
$this->addError("{$item} already exists.");
}
break;
}
}
}
}
if(empty($this->_errors)) {
$this->_passed = true;
}
return $this;
}
private function addError($error) {
$this->_errors[] = $error;
}
public function errors() {
return $this->_errors;
}
public function passed() {
return $this->_passed;
}
}
?>
As per your question, $count is a variable (array/variable) and you are calling a member function on it.
But, its not an object.
count() is in built PHP function.
You need to change:
if ($check->count()) {
to
if (count($check)) {
count()
You want to do count($check). $check is not a class.

PHP Form validation returning strange value

I recently made a very simple MVC'ish framework for my own. Now im trying to expand that framework with some classes, so i can save some time in the future. The class i am trying to make now is a form validation class. I thought it was working quite fine, untill i made a function to check for the minimum length of a string.
The class :
<?php
/**
* Form Validation Class
*/
class formValidation
{
private $errorMessages = array();
private $method;
public $errorString;
public $validationRules = array();
public function setMethod($method)
{
$this->method = $method;
}
public function setRules($rules)
{
$this->validationRules = $rules;
}
public function run()
{
if (!empty($this->method)) {
foreach ($this->method as $fieldname => $fieldvalue) {
foreach ($this->validationRules as $rule) {
if ($rule['field'] == $fieldname) {
foreach ($rule as $option => $rulevalue) {
switch ($option) {
case 'required':
if (!$this->checkRequired($fieldvalue)) {
$this->errorMessages[] = $rule['name'] . " is a required field";
}
break;
case 'letters_numbers':
if (!$this->checkLettersNumbers($fieldvalue)) {
$this->errorMessages[] = $rule['name'] . " may only contain letters and numbers";
}
case 'min_length':
if (!$this->checkMinLength($fieldvalue, $rulevalue)) {
$this->errorMessages[] = $rule['name'] . " must contain at least $rulevalue characters";
}
}
}
}
}
}
if (!empty($this->errorMessages[0])) {
return false;
} else {
return true;
}
} else {
return false;
}
}
// Checks
private function checkRequired($value) // Makes a field mandatory
{
if ($value == "") {
return false;
} else {
return true;
}
}
private function checkLettersNumbers($value) // Allow Letters and Numbers only
{
return preg_match('/^[A-Za-z\s ]+$/', $value);
}
private function checkMinLength($value, $minlength) // Check input for minimum length
{
if (strlen($value) < $minlength) {
return false;
} else {
return true;
}
}
// Error Handling Functions
private function makeErrorString($prelimiter = '<li>', $delimiter = '</li>') // Build all the errors into a string
{
if (!empty($this->errorMessages[0])) {
$errors = "";
foreach ($this->errorMessages as $message) {
$errors .= $prelimiter;
$errors .= $message;
$errors .= $delimiter;
}
$this->errorString = $errors;
return true;
}
}
public function ValidationErrors() // Return the error string
{
if ($this->makeErrorString()) {
return $this->errorString;
}
}
/**
* End of Class
**/
}
/**
* End of formValidation.php
**/
?>
And my controller file :
<?php
/**
* Homepage Controller
* #copyright 2012
*/
class home extends SimpleController
{
public function index()
{
$view = new view('home');
$val = new formValidation();
$val->setMethod($_POST);
$rules = array(
array(
'field' => 'test',
'name' => 'Test',
'required' => true,
'letters_numbers' => true,
'min_length' => '5'
),
array(
'field' => 'bla',
'name' => 'Trololol',
'required' => true
)
);
$val->setRules($rules);
if (!$val->run()) {
echo $val->ValidationErrors();
}
}
}
?>
In my view i have a form with 2 fields, test and bla. When i submit the form when it's empty, the checkMinLength() functions returns 2 value's :
Test must contain at least 1 characters
Test must contain at least 5 characters
First of all, where is it getting that 1 from, and 2nd why is it showing 2 messages for the same function ? I just can't find out why.
Hope you guys can help me out!
(The echo in the controller is just for demo)
Thanks!
You forgot a break in your switch, so you're falling through from the letters_numbers case into the min_length case.
The "rule value" for your letters_numbers rule is true, which converts to a string as 1.

Accessing $_POST array from objects called on page

I have a page that receives POST data from a form. I also have a form validation class that attempts to access the $_POST array when a FormValidation object is created on the page. However, the FormValidation object does not seem to have access to the $_POST array. Why is this happening, and how can I fix this?
EDIT: Added code :)
This code is from register.php
if($_SERVER['REQUEST_METHOD'] == 'POST')
{
var_dump($_POST);
$errors = validate_form();
if(count($errors) > 0)
{
display($errors);
}
else
{
act();
}
}
else
{
display();
}
function validate_form()
{
$validator = new FormValidation('POST');
$validator->add_field('first_name', 'First Name');
$validator->add_field('last_name', 'Last Name');
$validator->add_field('email_address', 'Email Address');
$validator->add_field('password', 'Password');
$validator->add_field('password_confirmation', 'Password Confirmation');
$validator->add_rule('first_name', 'required');
$validator->add_rule('last_name', 'required');
$validator->add_rule('email_address', 'required');
$validator->add_rule('email_address', 'is_valid_scarsdaleschools_email');
$validator->add_rule('password', 'required');
$validator->add_rule('password_confirmation', 'required');
$validator->add_rule('password_confirmation', 'matches', array('password', 'Password'));
return $validator->validate();
}
The form validation code looks like this
class FormValidation
{
var $fields;
var $rules; //Associative array that maps field_name to array of rules
var $errors;
var $form_method_type;
function FormValidation($form_method_type)
{
$this->form_method_type = strtoupper($form_method_type);
$this->fields = array(); //maps fields to field labels
$this->rules = array();
$this->errors = array();
}
function validate()
{
foreach(array_keys($this->fields) as $field_name)
{
if(!array_key_exists($field_name, $this->rules))
{
continue;
}
foreach(array_keys($this->rules[$field_name]) as $rule_name)
{
call_user_func_array(array($this, $rule_name), $this->rules[$field_name][$rule_name]);
}
}
return $this->errors;
}
function add_field($field_name, $field_label)
{
$this->fields[$field_name] = $field_label;
}
function add_rule($field_name, $rule_name, $parameters=array())
{
if(!isset($this->rules[$field_name]))
{
$this->rules[$field_name] = array();
}
array_unshift($parameters, $field_name, $this->fields[$field_name]);
$this->rules[$field_name][$rule_name] = $parameters;
}
function var_isset($field_name)
{
global ${'$_' . $this->form_method_type};
var_dump(${'$_' . $this->form_method_type}[$field_name]);
return isset(${'$_' . $this->form_method_type}[$field_name]);
}
function get_value($field_name)
{
global ${'$_' . $this->form_method_type};
return ${'$_' . $this->form_method_type}[$field_name];
}
////////////////////////////////////////////////////////////
/////RULES//////////////////////////////////////////////////
////////////////////////////////////////////////////////////
function required($field_name, $field_label)
{
if(!$this->var_isset($field_name))
{
$this->errors[$field_name] = "$field_label is a required field";
}
}
function is_valid_email($field_name, $field_label)
{
if($this->var_isset($field_name))
{
if(!validEmail($this->get_value($field_name)))
{
$this->errors[$field_name] = "$field_label requires a valid email address";
}
}
}
function is_alpha($field_name, $field_label)
{
if($this->var_isset($field_name))
{
if(!ctype_alpha($this->get_value($field_name)))
{
$this->errors[$field_name] = "$field_label requires alphabetical characters only";
}
}
}
function is_alphanumeric($field_name, $field_label)
{
if($this->var_isset($field_name))
{
if(!ctype_alnum($this->get_value($field_name)))
{
$this->errors[$field_name] = "$field_label requires alphanumeric characters only";
}
}
}
function is_integer_number($field_name, $field_label)
{
if($this->var_isset($field_name))
{
if(!is_int($this->get_value($field_name)) || preg_match('[-+]?[0-9]+', $this->get_value($field_name)) == 0)
{
$this->errors[$field_name] = "$field_label must be an integer";
}
}
}
function is_float_number($field_name, $field_label)
{
if($this->var_isset($field_name))
{
if(!is_float($this->get_value($field_name)) || preg_match('[-+]?[0-9]*\.?[0-9]+', $this->get_value($field_name)) == 0)
{
$this->errors[$field_name] = "$field_label must be a number";
}
}
}
function is_valid_scarsdaleschools_email($field_name, $field_label)
{
if($this->var_isset($field_name))
{
if(!validEmail($this->get_value($field_name)))
{
$this->errors[$field_name] = "$field_label requires a valid email address";
}
$email = $this->get_value($field_name);
if(!(endsWith($email, 'scarsdaleschools.org', $case=false) || endsWith($email, 'scarsdaleschools.com', $case=false) || endsWith($email, 'scarsdaleschools.k12.ny.edu', $case=false)))
{
$this->errors[$field_name] = "$field_label requires a Scarsdale Schools email address";
}
}
}
function max_length($field_name, $field_label, $max_length)
{
if($this->var_isset($field_name))
{
if(strlen($this->get_value($field_name)) > $max_length)
{
$this->errors[$field_name] = "$field_label cannot be longer than $max_length characters";
}
}
}
function min_length($field_name, $field_label, $min_length)
{
if($this->var_isset($field_name))
{
if(strlen($this->get_value($field_name)) > $min_length)
{
$this->errors[$field_name] = "$field_label must be at least $min_length characters";
}
}
}
function matches($field_name, $field_label, $match_field_name, $match_field_label)
{
if($this->var_isset($field_name) && !$this->var_isset($match_field_name))
{
$this->errors[$field_name] = "$field_label must match $match_field_label";
}
elseif(!$this->var_isset($field_name) && $this->var_isset($match_field_name))
{
$this->errors[$field_name] = "$field_label must match $match_field_label";
}
if($this->var_isset($field_name) && $this->var_isset($match_field_name))
{
if(strcmp($this->get_value($field_name), $this->get_value($match_field_name)) != 0)
{
$this->errors[$field_name] = "$field_label must match $match_field_label";
}
}
}
}
Thanks for the help!
There is a small error in your code. What you were writing was essentially $$_POST. You'll need to remove the extra dollar sign from the variable name (corrected methods below). In addition, you needn't worry about calling global $_POST; as $_POST is a superglobal, or automatic global.
Update: Retrieving $_POST via ${'_' . $this->form_method_type} does not seem to work. The code I sent you works OUTSIDE of the class, but not inside. I wanted to make sure you understood my findings, and the distinction. So while ${'_' . $formMethodType} works outside of the class, inside you'll have to use something like this:
const TYPE_POST = 'POST';
const TYPE_GET = 'GET';
const TYPE_SESSION = 'SESSION';
const TYPE_SERVER = 'SERVER';
const TYPE_REQUEST = 'REQUEST';
public $fields = array();
public $rules = array();
public $errors = array();
public function __construct($formMethodType)
{
$r = new ReflectionClass($this);
$constants = $r->getConstants();
$formMethodType = strtoupper($formMethodType);
if (!array_key_exists('TYPE_' . $formMethodType, $constants)) {
throw new InvalidArgumentException('Could not find type matching $formMethodType : ' . $formMethodType);
}
$this->form_method_type = $formMethodType;
}
public function var_isset($field_name)
{
$values = $this->get_values();
var_dump($values[$field_name]);
return isset($values[$field_name]);
}
public function get_value($field_name)
{
$values = $this->get_values();
return $values[$field_name];
}
public function get_values()
{
switch ($this->form_method_type) {
case self::TYPE_POST:
$values = $_POST;
break;
case self::TYPE_GET:
$values = $_GET;
break;
case self::TYPE_REQUEST:
$values = $_REQUEST;
break;
case self::TYPE_SERVER:
$values = $_SERVER;
break;
case self::TYPE_SESSION:
$values = $_SESSION;
break;
}
return $values;
}
We haven't yet seen any code posted, but I'll make a recommendation about using dependency injection to get the $_POST data into your form validation class, rather than accessing the superglobal from inside the class.
Since you can't always rely on $_POST being populated correctly when you are testing your code, it is advisable to inject the contents of $_POST as a parameter to the constructor of a class where it will be used. This makes it easier to debug later on.
class MyClass {
// Public property to hold post array data
public $postdata;
// constructor receives $_POST as a parameter
function __construct($param1, $param2, $postdata) {
//
$this->postdata = $postdata;
}
}
// Instantiate the class with $_POST injected
$x = new MyClass($a, $b, $_POST);
ADDENDUM after code posted
I don't see any method in your class that actually calls the get_value() method when validating. It's unclear if you are ever accessing the contents of $_POST in that class at all other than in the var_isset() and get_value() methods.
/**
* This should work for $_REQUEST and $_POST the mysql_real_escape_string
* was added to escape urls. It is best not to allow URLs as parameters.
*/
foreach( $_POST as $key=> $val)
{
${$key} = mysql_real_escape_string($val);
}

Categories