How to validate multiple inputs with PHP - php

I am using the following code to validate integer input fields in my form:
if (isset($_POST['MaxiVegXP']) && ctype_digit($_POST['MaxiVegXP']))
{
$MaxiVegXP = $_POST['MaxiVegXP'];
} else {
$MaxiVegXP = FALSE;
}
I have another 20 or so similar form input fields. Is there a quicker way of doing this with a PHP loop? I'd rather not do the above for another 20 input fields :-)

I would do something like #Simply Dread, but with a slight improvement, so I could explicitly indicate which fields needed to be fixed:
$validFields = array('field1' => true, 'field2' => true, 'field3' => true, ..., 'fieldN' => true);
foreach ($validFields as $field => $valid) {
if (!isset($_POST[$field]) && !ctype_digit($_POST[$field])) {
$validFields[$field] = false;
}
}
With this information, I can now show errors on the appropriate fields instead of only saying that there is a problem.

You could iterate over all fields for example:
foreach ($_POST as $key=>$value){
if (isset($_POST[$key]) && ctype_digit($_POST[$key])) {
$$key = $value;
} else {
$$key = FALSE;
}
}
But I would instead put the code in a function and call the fuction excplicitly for every post variable:
function isDigit($value) {
if (isset($value) && ctype_digit($value)) {
return true;
}
return false;
}
$MaxiVegXP = isDigit($_POST["MaxiVegXP"]) ? $_POST["MaxiVegXP"] : false;

An option would be to create an array of the field names and loop over it. Doing it this way will ensure all fields have to be set and are digits. Check the validate variable afterwards and you'll know if it was successful. :-)
$fieldArray = array('fieldOne', 'fieldTwo', 'fieldThree');
$validate = true;
foreach ($fieldArray as $field) {
if (!isset($_POST[$field]) && !ctype_digit($_POST[$field])) {
$validate = false;
}
}

Is there a quicker way of doing this with a PHP loop?
there's a quicker to do this without a PHP loop:
I would use filter_input_array. This code will assign null to the value if it does not pass the filter. It's quite practical, you just have to add the name of the variable and it's desired filter in the array.
$vars = filter_input_array(INPUT_POST,array (
'MaxiVegXP'=>FILTER_VALIDATE_INT,
'myVar'=>FILTER_DEFAULT,
// or FILTER_VALIDATE_INT. you can also define validator callbacks if need be
));
here you define the keys you wish to get from the input ($_POST in this example, but you can use INPUT_GET to get variables from the $_GET superglobal). You can also define more advanced options in the array to define a min or max range for your inputs, for instance
$vars = filter_input_array(INPUT_POST,array (
'MaxiVegXP'=>array(
'filter'=>FILTER_VALIDATE_INT,
'options'=>array('min_range'=>1, 'max_range'=>10),
),
));
the usefulness is that you don't have to verify manually for each key if they exist and what type they're of, filter_input_array takes care of that once you've defined your array of accepted value

Related

Why does my code return multiple echo strings

Whenever I submit my form, it returns three times "Good" as "GoodGoodGood" and I'm trying to figure out why. The ony thing I know, that it has to do something with Arrays.
check.php checks if all 3 inputs are not empty, if everthing is fine it echo'es "Good".
class Check {
public function mty() {
global $required;
global $field;
foreach($required as $field) {
if (empty($_POST[$field])) {
//Code...
} else {
echo "Good";
}
}
}
}
submit.php
$check = new Check;
//Gets names of inputs
$required = array('name', 'price', 'id');
if(isset($_POST['submit'])) {
$check->mty();
}
I'm new to OOP, just want to find a fix for the problem. Is there anything I can improve in this code?
The issue is that you're echoing "good" on each iteration in your loop.
You can create a variable that hold the state and check that and echo after the loop instead:
// The variable that keeps the state
$success = true;
foreach($required as $field) {
if (empty($_POST[$field])) {
// Set the state as false
$success = false;
}
}
// If state is true, no value was empty and we echo 'Good'... once.
if ($success) {
echo 'Good';
}
As others have mentioned, using global should be avoided when ever possible (which is always if you're structure is sound).
There's also the issue of you using global $field; while using $field in your foreach loop as well. If you're planing to use $field you've imported using global $field; in that method, you should use another name in your foreach. If you're not planing on using it, remove global $field;.
I prefer using the array_filter() to get only non-empty values and compare the count of that against the original $_POST count
<?php
# pretend like this was what was posted
$posted = [
'foo' => 'bar',
'bar' => 'foo',
'treybake' => 'is awesome?'
];
# your GLOBALS
$required = ['foo', 'treybake'];
# compare the count of the array without any empty elements
# vs original post count
if (count(array_filter($posted, function($el){return (!empty($el));})) === count($posted)) {
echo 'good';
} else {
echo 'something bad';
}

Creating a function to check form data with PHP

I've created an array that contains a form data (the form and php scripts are in a single php file).
I need to create a function to specify which one of the array elements are empty.
This is my code:
if(isset($_POST['submit'])){
$data=array("username"=>$_POST['username'],
"email"=>$_POST['email'],
"password1"=>$_POST['password1'],
"password2"=>$_POST['password2'],
"gender"=>$_POST['gender']);
check($data);
}
function check(){
if(isset($_POST['username']) && isset ($_POST['email']) && isset ($_POST['password1'])){
echo 'ok';
}
else{
echo 'missing';
}
}
Hi #Sina you didn't pass the param $data in the function definition.
<?php
if (isset($_POST['submit'])) { //only if form is submitted
$data = array(
'username' => $_POST['username'],
'email' => $_POST['email'],
'password1' => $_POST['password1'],
'password2' => $_POST['password2'],
'gender' => $_POST['gender']
);
check($data);
}
/**
* #description: validates the form data
* #return none
* #params array($data)
*/
function check($data) {
foreach ($data as $key => $value) {
if (empty($value)) {
echo ucwords($key)." is empty.<br/>";
}
}
}
?>
Thanks & Regards,
Vivek
Just use foreach :
function check($data)
{
foreach($data as $key => $value)
{
echo $key . isset($data[$key]) ? ' Ok' : ' Missing';
}
}
Edit : Fixed function with parameter
There are different ways of solving this, you can use foreach with empty() and a second array to contain the empty elements list.
Follow these steps:
Use foreach to get the values
Read index value and check if (empty($_POST[$key]))
If it's empty, either echo it or save it in a second array to use it later.
The following implementation is one suggestion but have a read at this good article on security and validations.
$_POST exists?
define a list of keys ( to iterate )
do validations in loop ie.isset(),is_null(),empty(),striptags/slash, sanitize etc.
Example:
if(empty($_POST)) {
// handle error ie. redirect
}
// define required keys or as constants using define();
$post_keys = array(
'username',
'email"'
'password1',
'password2',
'gender'
);
foreach($post_keys as $k => $v) {
// _isValid() is optional
// ie. or revalidate email format, empty string, blah etc.
// if(!isset($_POST[$k]) || !_isValid($k, $v)) { .. }
if(!isset($_POST[$k]) {
// handle error
}
}
// everything ok, do stuffs ie.$_POST['username'];
Hope this helps.

Laravel only validate items that are posted and ignore rest of validation array

For a project with Laravel 4.1 I have a little UI issue I'd like to solve.
Some inputs make an ajax call to laravel on blur and that works fine. It simply sends it's value. In laravel I then check with the validator.
public function validate() {
if(Request::ajax()) {
$validation = Validator::make(Input::all(), array(
'email' => 'unique:users|required|email',
'username' => 'required'
));
if($validation->fails()) {
return $validation->messages()->toJson();
}
return "";
}
return "";
}
Although this works, the json string also contains fields I have no need to check. To be precise this is the feedback I get:
{"email":["The email field is required."],"username":["The username field is required."]}
But seeing it is on blur I only want the one I'm actually checking in return. So if i'm blurring email I want a return of:
{"email":["The email field is required."]}
Now I know it's obviously because my array contains multiple fields, but I don't feel like writing a complete validation for each possible input I ever make.
My question is: can I somehow only get a return of the post values that are actually posted, even though the value might be null and not get rest of the array back.
Try this (untested, feel free to comment/downvote if it doesn't work) :
// Required rules, these will always be present in the validation
$required = ["email" => "unique:users|required|email", "username" => "required"];
// Optional rules, these will only be used if the fields they verify aren't empty
$optional = ["other_field" => "other_rules"];
// Gets input data as an array excluding the CSRF token
// You can use Input::all() if there isn't one
$input = Input::except('_token');
// Iterates over the input values
foreach ($input as $key => $value) {
// To make field names case-insensitive
$key = strtolower($key);
// If the field exists in the rules, to avoid
// exceptions if an extra field is added
if (in_array($key, $optional)) {
// Append corresponding validation rule to the main validation rules
$required[$key] = $optional[$key];
}
}
// Finally do your validation using these rules
$validation = Validator::make($input, $required);
Add your required fields to the $required array, the key being the field's name in the POST data, and the optional fields in the $optional array - the optional ones will only be used if the field exists in the submitted data.
You can also use Laravel requests in a much cleaner way
public function rules(){
$validation = [];
$input = Request::all();
if (array_key_exists('email', $input)) {
$validation['email'] = 'unique:users|required|email';
}
if (array_key_exists('username', $input)) {
$validation['username'] = 'required|min:6';
}
return $validation;
}
I found it. It's going to be something like this:
if(Request::ajax()) {
$arr = array();
$arr['email'] = 'unique:users|required|email';
$arr['username'] = 'required|min:6';
$checks = array();
foreach($arr as $key => $value) {
if(Input::has($key)) {
$checks[$key] = $value;
}
}
if(count($checks)) {
$validation = Validator::make(Input::all(), $checks);
if($validation->fails()) {
return $validation->messages()->toJson();
}
}
return "ok";
}
return "";

PHP filter_var: How to make sure the user provides correct data types - true or false only

I want to compare two arrays, one is set by default and another by user input.
When I have set a boolean value only in the default so I want to make sure the user won't use string or number. for instance, 'truex' or '1' is not acceptable.
Below is my sample of code,
$default = array(
"randomise" => false,
"id" => null
);
$config = array(
"randomise" => truex
);
function process_array($default,$config)
{
# Loop the array.
foreach($default as $key => $value)
{
if ((filter_var($default[$key], FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE) === NULL) && (filter_var($config[$key], FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE) === NULL))
{
return 'true or false only';
}
}
# Return the result.
return $array;
}
print_r(process_array($default,$config));
but this code returns 'true or false only' even though the user provides the correct data type. how can I fix this?
Alright first up you need to check that $config contains the key in $default. [Asside: If $config is user supplied... they could never user-supply an object like that, perhaps you meant $config=array("randomize"=>"truex");.. unless by user supplied you mean some other developer as the user (not a web user)).
Second of all $config['id'] will always fail the test as you've written it (because it's not a boolean).
So, I'm trying to guess at what you're doing here but I think this is what you want...
$default = array("randomise"=>false,"id"=>null);
//Example input
$config = array("randomise"=>"truex");
function process_array($default,$config) {
foreach($default as $key => $value) {
if (is_bool($default[$key])
&& isset($config[$key])) {
//Update the array with the filtered value
$config[$key]=filter_var($config[$key],FILTER_VALIDATE_BOOLEAN,
FILTER_NULL_ON_FAILURE);
if ($config[$key]===null)
return '$key can be true or false only';
}
}
}
return $array;
}
print_r(process_array($default,$config));

changing object in loop in Datamapper ORM

I'm trying to save a long form in Codeigniter's Datamapper. I'm able to save the form if I pass the value like this
$t->brandName = $this->input->post('brandName');
$t->specialNotes = $this->input->post('specialNotes');
$t->name = $this->input->post('name');
Now if I call save method it works
$t->save();
Since the form is big I tried to add object values in foreach
$a = get_object_vars($t);
foreach ($a['stored'] as $k => $val){
$t->$k = $this->input->post("$k");
}
however if I call the $t->save() it doesn't work.
I'm not sure what $a['stored'] represents, but it's nothing that's default in Datamapper.
Why don't you do it the opposite way, looping through the post keys?
foreach ($_POST as $key => $val)
{
$t->$key = $this->input->post($key);
}
$t->save();
Note: Any columns that don't exist will just be ignored by Datamapper.
I actually wrote a Datamapper extension for this:
class DM_Data {
function assign_postdata($object, $fields = NULL)
{
// You can pass a different field array if you want
if ( ! $fields)
{
$fields = $object->validation;
}
foreach ($fields as $k => $data)
{
$rules = isset($data['rules']) ? $data['rules'] : array();
if ( ! isset($_POST[$k])) continue;
// Cast value to INT, usually for an empty string.
if (in_array('integer', $rules))
{
$object->$k = (integer) $_POST[$k];
}
// Do other manipulation here if desired
else
{
$object->$k = $_POST[$k];
}
}
return $object;
}
}
You can use $t->assign_postdata()->save(), and optionally pass an array of fields to update to the function (in the datamapper validation format). However, I forget why I use that... but I removed some of the custom stuff. This should be useful for you if you are doing this a lot. It definitely saves me time.

Categories