Accessing $_POST array from objects called on page - php

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);
}

Related

Argument value is not being passed in PHP classes

I have a scenario where I want to create a user using Object Oriented PHP8, I have my users.php page where I have the form and this issue seems to be that I do not think the method from my object form ($objForm) are being passed in correctly to my object validation ($objValidation):
users.php
<?php
use A\B\App\Session;
use A\B\App\Login;
use A\B\App\User;
use A\B\App\Form;
use A\B\App\Validation;
require_once("../../vendor/autoload.php");
$session = new Session();
if(!$session->isLogged()) {
Login::redirectTo("login");
}
$objForm = new Form();
// passing in the object to validation
$objValidation = new Validation($objForm);
$objUser = new User();
if($objForm->isPost("name")) {
$objValidation->expected = ["name"];
$objValidation->required = ["name"];
$objValidation->special = ["email" => "email"];
$objValidation->postFormat = ["password" => "password"];
$email = $objForm->getPost("email");
$existingUser = $objUser->getUserByEmail($email);
if($existingUser) {
$objValidation->addToErrors("user_exists");
}
if($objValidation->isValid()) {
echo "good";
} else {
echo "bad";
}
}
?>
<form action="" method="post">
<p>
<input type="text" name="name" placeholder="User name" required="">
</p>
<?php echo $objValidation->validate('user_exists'); ?>
<p>
<input type="email" name="email" placeholder="User email" required="">
</p>
<p>
<input type="password" name="password" placeholder="Password" required="">
</p>
<p>
<input type="submit" name="" value="Add user">
</p>
</form>
I am simply trying to echo out a yes or no to see if it passes this point so I am not actually calling a method to create a user yet since the code is failing before.
below are my 2 classes:
Form.php
<?php
declare(strict_types = 1);
namespace A\B\App;
class Form
{
public function isPost(string $field): bool
{
if(!empty($field)) {
if(isset($_POST[$field])) {
return true;
}
return false;
} else {
if(!empty($_POST)) {
return true;
}
return false;
}
}
public function getPost(string $field)
{
if(!empty($field)) {
return $this->isPost($field) ? strip_tags($_POST[$field]) : null;
}
}
public function getPostArray(array $field): array
{
$out = [];
if($this->isPost()) {
foreach($_POST as $key => $value) {
if(!empty($field)) {
if(in_array($key, $expected)) {
$out[$key] = strip_tags($value);
}
} else {
$out[$key] = strip_tags($value);
}
}
}
return $out;
}
}
and here is the validation class:
Validation.php
<?php
declare(strict_types = 1);
namespace A\B\App;
class Validation
{
private array $error = [];
public array $message = ["user_exists" => "This user exists in the Db"];
public array $expected = [];
public array $required = [];
public array $post = [];
private $objForm;
public array $test = [];
public array $postRemove = [];
public array $postFormat = [];
public array $special = [];
public function __construct(Form $form)
{
$this->objForm = $form;
}
public function process()
{
if($this->objForm->isPost() && !empty($this->required)) {
$this->post = $this->objForm->getPostArray($this->expected);
if(!empty($this->post)) {
foreach($this->post as $key => $value) {
$this->check($key, $value);
}
}
}
}
public function check($key, $value)
{
if(!empty($this->special) && array_key_exists($key, $this->special)) {
$this->checkSpecial($key, $value);
} else {
if(in_array($key, $this->required) && empty($value)) {
$this->addToErrors($key);
}
}
}
public function checkSpecial($key, $value)
{
switch($this->special[$key]) {
case 'email':
if(!$this->isEmail($value)) {
$this->addToErrors($key);
}
break;
}
}
public function isEmail($email)
{
if(!empty($email)) {
$result = filter_var($email, FILTER_VALIDATE_EMAIL);
return !$result ? false : true;
}
return false;
}
public function isValid()
{
$this->process();
if(empty($this->errors) && !empty($this->post)) {
// remove unwanted fields
if(!empty($this->postRemove)) {
foreach($this->postRemove as $value) {
unset($this->post[$value]);
}
}
// format required fields
if(!empty($this->postFormat)) {
foreach($this->postFormat as $key => $value) {
$this->format($key, $value);
}
}
return true;
}
return false;
}
public function format($key, $value)
{
switch($value) {
case 'password':
$this->post[$key] = Login::passwordEncrypt($this->post[$key]);
break;
}
}
public function addToErrors($key)
{
$this->errors[] = $key;
}
public function validate($key)
{
if(!empty($this->errors) && in_array($key, $this->errors)) {
return $this->wrapWarn($this->message[$key]);
}
}
public function wrapWarn($mess)
{
if(!empty($mess)) {
return "<span class=\"warn\" >{$mess}</span>";
}
}
}
I have tested other dummy functions from validations.php and form.php and both work so the issue is definitely between the communication with these 2 classes. The process method is not recognizing or not getting values from the $this->objForm->isPost() call. Here is the error message I get where its telling me no value is being passed in:
Fatal error: Uncaught ArgumentCountError: Too few arguments to
function A\B\App\Form::isPost(), 0 passed in
/Applications/MAMP/htdocs/project/src/App/Validation.php on line 41
and exactly 1 expected in
/Applications/MAMP/htdocs/project/src/App/Form.php:10 Stack trace:
#0 /Applications/MAMP/htdocs/project/src/App/Validation.php(41): A\B\App\Form->isPost() #1
/Applications/MAMP/htdocs/project/src/App/Validation.php(94):
A\B\App\Validation->process() #2
/Applications/MAMP/htdocs/project/src/Pages/users.php(36):
A\B\App\Validation->isValid() #3 {main} thrown in
/Applications/MAMP/htdocs/project/src/App/Form.php on line 10
Note: I have not been applying type declarations/hints to everything yet because of being stuck.
In order to not change too much the codebase (change all the references of the method), you should change the signature of the isPost() function in this way:
public function isPost(string $field = ""): bool

Assigning the property $action of a class ($this) to an variable $conf, why it is an array?

There is the following function in the controller.php of framework thinkphp used in a project, where there is this line of codes: "$conf = $this->$action".
"if (property_exists($this, $action))" is checking if there exists property $action in the class $this. Form the next line of codes "if (key_exists('login', $conf))", it looks to me that $conf is an array.
My question is: what exactly is "$conf = $this->$action" doing, assigning an array (the property $action? why $action is an array?) to the variable $conf?
public function checkAccessControl()
{
if (Config::get('frame.controller.checkAccessControl.exec')) {
$action = $this->request ->action(true);
if (property_exists($this, $action)) {
$conf = $this->$action;
if (key_exists('login', $conf)) {
if ($conf['login'] === true && $this->if_login === false) {
$this->access_control_check = false;
$this->response(["error"=>"未登录用户无权访问"],[],401,'json');//要求用户的身份认证
} else {
$this->access_control_check = true;
}
} else {
$this->access_control_check = false;
$this->response(["error"=>"代码错误:未标注访问类型"],[],500);//服务器内部错误,无法完成请求(未在控制器中标注login的访问控制)
}
} else {
$this->access_control_check = false;
$this->response(["error"=>"代码错误:未标注访问控制"],[],500,'json',['action'=>$this->request->action(true)]);//服务器内部错误,无法完成请求(未在控制器中标注方法的访问控制)
}
} else {
$this->access_control_check = Config::get('frame.controller.checkAccessControl.default.access_control_check');
}
}

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.

Checking which function is true and false

Sorry for the terrible headline, let me try to explain below.
I have written a bunch of small functions that either returns true or false.
validateName()
validateEmail()
validateAddr()
validateBirtd()
validateUsername()
Now I am looping through a lot of data imported with a CSV file, and checkin which data is valid or not (returns true or false).
I do it this way:
if (validateName($data[0]) == true AND validateEmail($data[1]) == true AND validateAddr($data[3]) == true AND validateBirtd($data[5]) == true AND validateUsername($data[6])==true) {
// create array to import etc etc
}else{
// create other array with data who failed validation, to show user later..etc etc
}
My question is - is there a more clever way to do this? Would it be possible to create a list of for each failed validation ? Say 3 entrys has fails the validateEmail() function, and 10 both fails validateEmail and validateName().
Would there be a way for me to sort this so I can tell the user "these entrys failed email validation" and "these entrys failed Name and email validation".
I thought about validating one field at a time, but this way I would have duplicates if one entry has more than one validation error.
Would be cool if there was some kind of logic that I don't know of where I could do this
You could create a function.
function validate($data) {
$errors = array();
$fields = array('Name', 'Email', 'Addr', 'Birtd', 'UserName');
foreach ($fields as $i => $field) {
$func = 'validate'.$field;
if (!$func($data[$i])) {
$errors[] = $field;
}
}
return $errors;
}
$errors = validate($data);
if (empty($errors)) {
// create array to import etc etc
} else {
// errors
echo 'There are errors with ' . implode(',', $errors);
}
You can use Iterators to get CSV content and filter at the same time. you can also add different callback to each CSV index
Example
$csv = new CSVFilter(new CSVIterator("log.txt"));
$csv->addFilter(0, "validateName"); //<------------ Means validate Index at 0
$csv->addFilter(1, "validateEmail");
$csv->addFilter(2, "validateAddr");
$csv->addFilter(3, "validateBirtd");
$csv->addFilter(4, "validateName");
$csv->addFilter(5, "validateUsername");
foreach ( $csv as $data ) {
var_dump($data);
}
//To get Errors
var_dump($csv->getErrors());
CSV Filter
class CSVFilter extends FilterIterator {
protected $filter = array();
protected $errors = array();
public function __construct(Iterator $iterator) {
parent::__construct($iterator);
}
public function addFilter($index, Callable $callable) {
$this->filter[$index] = $callable;
$this->errors[$callable] = 0;
}
public function getErrors() {
return $this->errors;
}
public function accept() {
$line = $this->getInnerIterator()->current();
$x = true;
foreach ($this->filter as $key => $var ) {
if (isset($line[$key])) {
$func = $this->filter[$key];
$func($var) or $this->errors[$func] ++ and $x = false;
}
}
return $x;
}
}
CSVIterator
class CSVIterator implements \Iterator {
protected $fileHandle;
protected $line;
protected $i;
public function __construct($fileName) {
if (! $this->fileHandle = fopen($fileName, 'r')) {
throw new \RuntimeException('Couldn\'t open file "' . $fileName . '"');
}
}
public function rewind() {
fseek($this->fileHandle, 0);
$this->line = fgetcsv($this->fileHandle);
$this->i = 0;
}
public function valid() {
return false !== $this->line;
}
public function current() {
return array_map("trim", $this->line);
}
public function key() {
return $this->i;
}
public function next() {
if (false !== $this->line) {
$this->line = fgetcsv($this->fileHandle);
$this->i ++;
}
}
public function __destruct() {
fclose($this->fileHandle);
}
}
Simple Random Functions
function validateName($var) {
return mt_rand(0, 5);
}
function validateEmail($var) {
return mt_rand(0, 5);
}
function validateAddr($var) {
return mt_rand(0, 5);
}
function validateBirtd($var) {
return mt_rand(0, 5);
}
function validateUsername($var) {
return mt_rand(0, 5);
}
If you something a little more encapsulated, you can try this. It allows you to write different validators for each CSV file you may be validating. Additionally, you could write methods in either class that would allow you to perform additional tasks on each row. I just find it a little cleaner and easier to maintain than having a bunch of globally-named functions.
Note: I'm obviously using some pretty basic validator examples and exceptions. The idea here is that I'm providing a layout for you to follow; you can customize any specific behaviors however you'd like.
usage
$c = new UserCsvValidator('user_data.csv');
try {
$c->validate();
}
catch (Exception $e) {
echo $e->getMessage();
}
implementation; parent class
<?php
class CsvValidator {
private $filename;
private $fh;
protected $fields = array();
public function validate__construct($filename, ) {
$this->filename = $filename;
// open file
if ( ($this->fh = fopen($this->filename, 'r')) === false) {
throw new Exception("could not open file: {$this->filename}");
}
}
public function validate() {
while( ($row=fgetcsv($this->fh)) !== false) {
// create hash
if ( ($hash = array_combine($this->fields, $row)) === false) {
throw new Exception("invalid row" . print_r($row, true));
}
// validate
foreach ($hash as $field => $value) {
// determine method call
$method = "validate_{$field}";
if (!method_exists($this, $method)) {
throw new Exception("validation method not defined: {$method}");
}
// validate the field
if (call_user_func(array($this, $method), $value) === false) {
throw new Exception("invalid value for {$field}: {$value}");
}
}
}
}
}
implementation; subclass
<?php
class UserCsvValidator extends CsvValidator {
protected $fields = array('name', 'email', 'address', 'birth_date', 'username');
// example functions for each field
protected function validate_name($value) {
return !empty($value);
}
protected function validate_email($value) {
return strpos($value, '#') !== false;
}
protected function validate_address($value) {
return !empty($value);
}
protected function validate_birth_date($value) {
return date('Y-m-d', strtotime($value)) == $value;
}
protected function validate_username($value) {
return !empty($value);
}
}

Categories