consecutive if's in PHP - php

I'm doing some validation now in PHP, and I'm running allot of conditional statements, for example:
if ($this->email->isValid($email))
return false;
if ($this->username->isValid($username))
return false;
ect..
Is there a nice way to do this? Or do I just run ten If statements like the ones above?
I can't use switch obviously, but I'm looking for that type of solution..
P.S... I'm using Zend Framework for validation

You could OR them like this:
if(cond1||
cond2||
cond3||
cond4)
{
return false;
}

Doing something like this is called a Guardian clause. It can be improved so clauses that return the same value should be grouped together.
if ($this->email->isValid($email) || $this->username->isValid($username))
{
return false;
}
Or like this, if there are many (btw how I format the if is just so it can read better, any other way should be fine as well)
if (
$this->email->isValid($email) ||
$this->username->isValid($username) ||
$this->somethingelse()
)
{
return false;
}

If this is data from a form, take a look at Zend_Form, as recommended by a poster in your other question
I posted some example code which details adding validators to form elements

Just make sure that you put the most obvious validation at the top, so if its going to fail it will trip before it runs through every statement. Also, I don't like if statements without curly brackets, but then thats just a matter of opinion.

if ($this->email->isValid($email) ||
$this->username->isValid($username))
return false;

It is always good to use some var than multiple returns
In case these are the only return conditions. We dont need to check for all conditions. like check only for true conditions return false by default or vice-versa.
$result = false; //return false by default.
if (cond1 || cond2) { //check only for conditions which result in returning true. :)
$result = true;
}
return $result;
Cheers,
-Ratnesh

I would make them data members of my class. Obviously here you will have to have a form driven class. So here for example the email could be wrapped into a class and initialised with in the constructor of the class that has them as member variables. Now the email wrapper class will do validation for email on initialisation/construction.
IMHO that would look less cluttered and you can wrap up any validation or specific methods to the email-wrapper class.
I know it might be a sledge hammer in some context; so choose wisely!

Maybe something like this:
foreach( $form->getElements as $element => $value )
{
if( !$element->isValid( sanitize($value))){
return false;
}
}
BUT if you are using ZF this is your oneliner answer because you check all the form in one not individual fields:
$form = new My_Zend_Form(); // in the controller action that you send the form to
if ( $form->isValid($_POST)) {
// Success /// do whatever you want with the data
$data = $form->getValues();
} else {
//error
}

Do something like this:
$errlvl = 0;
if($errlvl == 0 && $this->email->isValid($email)){
$errlvl++;
}
if($errlvl == 0 && $this->username->isValid($username)){
$errlvl++;
}
// your validation list keeps going
if($errlvl > 0){
return false;
}
this will
Reduce redundancy because if there's an error in front, the following will not be checked.
you can keep adding on to the list
if you want to know how many errors occurred, you can remove $errlvl == 0 in the statements

Add all objects to an array and the iterate it (I guess you or Zend are using an interface "validator" or something like that each component (username, email, etc) implements the "isValid" method):
$validators = array();
$validators[] = $this->email;
$validators[] = $this->username;
foreach ($validators as $validator)
{
if (!$validator->isValid())
{
return false;
}
}

Related

How to assign values & keys to a string from an associative array (foreach) [duplicate]

Is there a safe way to auto assign the keys in a posted array? Below are two examples of wrong ways...
foreach( $_POST as $key => $value ) {
$$key = $value;
}
or
extract($_POST)
Is there a better way, or is it best to code:
$foo = $_POST('foo');
$bar = $_POST('bar');
....
for all 50 inputs on my form?
(the posted info will be inserted into a database).
One more cautious way of extracting all input fields at once is:
extract( $_POST, EXTR_OVERWRITE, "form_" );
This way all your input variables will be called $form_foo and $form_bar at least. Avoid doing that in the global scope - not because global is evil, but because nobody ever cleans up there.
However, since mostly you do that in a localized scope, you can as well apply htmlentities if for example you need all fields just for output:
extract(array_map("htmlspecialchars", $_POST), EXTR_OVERWRITE, "form_");
There is not a single reason to do it.
To handle user inputs an array is 100 times better than separate variables
I like an approach where you let dynamic getters and setters in a class do all the work for you. Here's how I would code it.
First, create a bass class to hold data:
class FormParameterHandler {
protected $parameters;
public function __construct($associative_array) {
$this->parameters = array();
foreach($associative_array as $key => $value) {
$this->{$key} = $value;
}
}
public function __get($key) {
$value = null;
if(method_exists($this, "get_$key")) {
$value = $this->{"get_$key"}();
} else {
$value = $this->parameters[$key];
}
return $value;
}
public function __set($key, $value) {
if(method_exists($this, "set_$key")) {
$this->{"set_$key"}($value);
} else {
$this->parameters[$key] = $value;
}
}
}
Next, create a specific class to use for some specific form where there is something special to validate. Use your freedom as a programmer here to implement it any way you want to. And remember, since we're using reflection to look for setter methods, we can write specific setter methods for known problem areas, like e.g. to check for equal passwords in a "register user" form:
class RegisterFormParameterHandler extends FormParameterHandler {
private $passwords_are_equal = null;
public function __construct($register_form_parameters) {
parent::__construct($register_form_parameters);
}
public function has_equal_passwords() {
return $this->passwords_are_equal;
}
public function set_password($password) {
$this->parameters['password'] = $password;
$this->compare_passwords();
}
public function set_password_repeat($password_repeat) {
$this->parameters['password_repeat'] = $password_repeat;
$this->compare_passwords();
}
private function compare_passwords() {
if(isset($this->parameters['password']) && isset($this->parameters['password_repeat'])) {
$this->passwords_are_equal = ($this->parameters['password'] === $this->parameters['password_repeat']);
}
}
}
Finally, use the derived class in a "register user" flow, to easily find out if the two entered passwords match:
$registerFormParameterHandler = new RegisterFormParameterHandler($_POST);
if($registerFormParameterHandler->has_equal_passwords()) {
print "are equal";
//register user
} else {
print "are not equal";
}
You can test this by creating an HTML form that has one input field with the name "password", and another input field with the name "password_repeat".
To access any of the form data, use your form data object variable name, followed by the access operator "dash larger than" -> , followed by the name of the parameter. In the example above, if there was an input field named "user_name", it would be accessed through a call to
$registerFormParameterHandler->user_name
Rr, if you have defined the name of the field you want to get in some other variable, use reflection:
$registerFormParameterHandler->{$settings['form_data_user_name']}
Have fun! :)
A safe way to extract variables into the local scope is not to. You're injecting variables into your local scope, which is a problem however you do it. Even if you limit the variables to only a few select ones that won't clash with other variable names in the scope now, if you start adding elements to your form you may be in trouble later.
Arrays are specifically for holding an unlimited amount of named values without crowding the variable namespace. Use them! You may have to type a little more, but that's par for the course.
While it is best to refer to them with $_POST['variablename'], it is possible to expand only the variables you are expecting.
$expected = array('name', 'telephone', /* etc */);
foreach ($_POST as $key => $value) {
if (!in_array($key, $expected)) {
continue;
}
${$key} = $value;
}
Or, I prefer this:
foreach ($_POST as $key => $value) {
switch ($key) {
case 'name':
case 'telephone':
/* etc. */
${$key} = $value;
break;
default:
break;
}
}
The answer to your question depends on the computer, language, and security knowledge of the programmer. The opening sequence of processing $_POST is kind of like the opening move in a game of chess. Many use foreach loops without realizing that foreach will make a copy of the contents of $_POST the way you have it used (Programming PHP: Chapter 5, p.128-129). Wouldn't it be funny if you caused a buffer overflow simply by using foreach!
One commenter implied that everything should just be worked with inside of the $_POST superglobal. There are some merits to this... However, forgetting cache memory for a moment, access to array values is slower than direct access to a variable.
Since you have fifty (50) controls to validate (with potentially large contents), I might not want to take that array access performance hit more than 50 times (the original access hits). Moreover, if you are concerned about writing secure input validation routines, keeping your dirty laundry (non-validated input) separate from your clean (validated input) laundry is a good idea. That said, you may need a clean array anyway (hence the $_POST advocate's response), but at least you are reducing risk in the process by keeping the hopefully good separate from the potentially bad.
Is there a safe way to auto assign the keys in a posted array?
I might start like this:
Function library for this example.
function all_controls_submitted($controls) {
$postKeys = array_keys($_POST);
foreach($controls as $key) {
if(! array_key_exists($key, $postKeys)) {
return false;
}
}
return true;
}
function all_controls_set($controls) {
foreach($controls as $key) {
if(! isset($_POST[$key])) {
return false;
}
}
return true;
}
if(is_array($_SERVER) && isset($_SERVER['REQUEST_METHOD'], $_SERVER[REQUEST_URI]) && $_SERVER['REQUEST_METHOD'] === 'GET' && $_SERVER['REQUEST_URI'] === '/contact.php') {
$newForm = true;
} elseif (is_array($_SERVER) && isset($_SERVER['REQUEST_METHOD'], $_SERVER['REQUEST_URI']) && $_SERVER['REQUEST_METHOD'] === 'POST' && $_SERVER['REQUEST_URI'] === '/contact.php') {
$newForm = false;
$controlNames = array('firstName', 'lastName', 'e-mail', 'company', 'subject', 'message', 'captcha');
define('NUM_CONTROLS_EXPECTED', count($controlNames)); //Seven (7)
if(is_array($_POST) && count($_POST) === NUM_CONTROLS_EXPECTED && all_controls_submitted($controlNames) && all_controls_set($controlNames)) {
//Begin input validation
}
} else {
header('location: http://www.nsa.gov');
}
Notice that I prep things with the $controlNames array, therefore I do not have to ask $_POST for the keys. After all, I should know them! :-) The two user-defined functions, all_controls_submitted() and all_controls_set() are two fundamental questions that should be asked before trying to use any values in $_POST (I say, anyway). Admittedly, I do use $_POST in all_controls_submitted(), but only to obtain the names of the controls submitted, not the values.
$postKeys = array_keys($_POST);
However, who is to say that the control names themselves could not be poisonous and in need of input validation?!! Same goes for values in $_SERVER. See, a chess game.
Is there a safe way to auto assign the keys in a posted array? I cannot tell you for certain, but perhaps something like the code above could help? You'd have the keys, at least.
Programming PHP: Chapter 5, p.125
Try this inbuilt method/function filter_input
Reference URL: php.net function filter input

Combining PHP Functions - Advanced Search?

I have to build an advanced search feature and some of it options are complex. For example:
is Online
have Comments
etc
To get this information, I can't make direct database queries. So, I need to build functions to do this.
Let's say... the user selects 4 or 5 options - how can I combine multiple functions results?
It doesn't make sense to do something like:
if(is_Online() && have_Comments()...)
Because I don't know which or how many options are selected... so I think there should be some dynamic alternative?
Thank you.
Difficult to provide a better answer without more detail, but this might help you. The following assumes that your if statement will proceed when each checkbox is either left unchecked or when the logic associated with that checkbox returns true.
I would be inclined to store each function in an array and call them dynamically based on the name of the field you're looking at.
<?php
$resultCheckers = array(
'is_Online' => function() { /* Is Online logic here */},
'have_Comments' => function() { /* Have Comments logic here */}
);
function IsUncheckedOrHasValue($parameter)
{
$result = true;
//Check if user has checked the box for this parameter
if(array_key_exists($parameter, $_POST))
{
//Check if this is a valid key in your $resultCheckers
if(array_key_exists($parameter, $resultCheckers))
{
//Run the result Checker
$result = $resultCheckers[$parameter]();
} else {
$result = false;
}
}
return $result;
}
?>
Your if statement would look something like this:
if(IsUncheckedOrHasValue('is_Online') && IsUncheckedOrHasValue('have_Comments'))
{
...
}
Which is a bit laborious to read, so if you wanted you could abstract it further into it's own function like this:
function IsMatch()
{
$isMatch = IsUncheckedOrHasValue('is_Online') &&
IsUncheckedOrHasValue('have_Comments') &&
IsUncheckedOrHasValue(...) &&
IsUncheckedOrHasValue(...);
return $isMatch;
}
So then your if statement would end up being
if(IsMatch())
{
...
}
NOTE: I'm a little confused that you're not passing any information about the result to your checking functions. Are you writing it Object Oriented and that information is available in the current object? Or perhaps you just omitted those extra parameters for brevity. In any event, I hope this helps you and it was fun to dip back into PHP after some time away from it :)

Server-side validating HTML form input with a long series of if / else statements - efficient?

Is it efficient to simply use a long series of nested if / else statements in PHP to validate user input from an HTML form?
So say there's two fields, I'm just approaching it like this:
if ( field one is formatted right ) {
if ( field one is long enough ) {
if ( field two is ok ) {
do stuff;
}
else {
echo "field two is not ok!";
}
}
else {
echo "field one is not long enough!";
}
}
else {
echo "field one is not formatted right!";
}
I hope you get the idea.
So when there are several fields and a lot of validation to do, and different kinds of validation for each field, this ends up being quite long.
Is this a bad way to deal with this?
what i usually do is something like:
$error_msg = '';
if (field1 not valid)
$error_msg .= 'Field One is not valid.<br>';
if (field2 not valid)
$error_msg .= 'Field two is not valid.<br>';
if ($error_msg == '')
{
// DO ALL YOUR VALID SUBMISSION STUFF HERE
}
I usually think its better to notify the user of all their errors at once instead of one at a time to annoy them.
That code should work, and one way to determine its efficiency would be to use profiling to actually measure how long it takes.
An alternative way to validate would be something like this:
function handle_submission(){
$field_1_validation_result=validate_field_1_value($field_1_value);
if($field_1_validation_result!==true)exit($field_1_validation_result);
$field_2_validation_result=field_2_validation_result($field_2_value);
if($field_2_validation_result!==true)exit($field_2_validation_result);
//Everything is right
do stuff
}
function validate_field_1_value($value){
if ( !field one is formatted right )return "field one is not formatted right";
if ( !field one is long enough )return "field one is not long enough";
return true;
}
function validate_field_2_value($value){
if( !field two is ok)return "field two is not ok"
return true;
}
Thinking forward there are definitely better ways you can approach this. For a start you can instead try to create something like a validation class with pre-defined validation methods.
Take for (a very rough) example:
class Validator {
public function validate($args) {
$errors = array();
//Make sure to do any santising you need too
foreach($args as $field=>$data) {
if ($response = $field($data))
$errors[$field] = $response;
//You could create break code here if you wanted
//to check if the form was invalid without detailed feedback
}
if (empty($errors)) {
return false;
}
return $errors;
}
private function email_field($data) {
$valid = true;
//perform a validation on email here, generate an $err_msg if it's not valid
if ($valid)
return false;
return $err_msg
}
}
$validator = new Validator();
//You probably want to explode or loop through the error messages
//Or for extra brownie points, use the key of each element in the array to place
//the error message intelligently within your HTML!
$validation_errs = $validator->validate($_POST);
if ($validation_errs)
print_r($validation_errs);
Combined with your form...
<form method="post" action="">
<input type="text" name="email_field" />
</form>
This could then be combined to provide your validation. The reason this may be better is that you could use this class throughout your site, meaning you don't have to duplicate your validation logic, and more importantly you don't have to have trails of nested logic for each form. You simply pass the post variables, your class will automatically run the validation that it requires, and give you back either an all clear (unintuitively, "false" here, sorry) or an array of validation error messages paired with the field name they came from.
Furthermore this then becomes useful when dealing with combining serverside and clientside validation, allowing you to use AJAX to call very specific, single field, validation queries to your PHP over AJAX and returning you the response that can be used (as long as you are doing enough with your output to ensure it is valid for AJAX communication).
So, when it comes to efficiency, it's not just about what is important now, or how negligible the performance differences might be...it's about how much time it will save you later, when your form changes, when your validation logic has to be altered, and when you need to reuse the same validation logic over and over again.
I think that formatting like this is easier to read and follow:
if ( field one is not formatted right ) {
echo "field one is not formatted right!"
} else if ( field one is no long enough ) {
echo "field one is not long enough!";
} else if ( field two is not ok) {
echo "field two is not ok!";
} else {
do stuff;
}
This is what I do most of the times:
$Errors = array();
if (field one is not formatted right)
$Errors[] = "Field one is not formatted right.";
if (field one is not long enough)
$Errors[] = "Field one is not long enough.";
if (field two is not ok)
$Errors[] = "Field two is not ok.";
if (empty($Errors)) {
do stuff;
} else {
foreach ($Errors as $Error) {
echo '<div class="error">' . $Error . '</div>';
}
}
This is similar to other answers only that I use an array to store the error messages so that I can format them easier.

More elegant way to write these conditions?

out of curiosity I'm wondering if there's a more elegant way to write the conditionals below? I can't see a shorter way of writing it but it feels pretty clunky, so any suggestions welcome!
// Check whether this page has any visuals
if (count($this->page->pagevisuals->find_all()) > 0)
{
// Ok to go ahead and assign
$visual = $this->page->pagevisuals->find_all();
}
// If this is a sub page, parent page may have visuals we can use
elseif (count($this->page->parent->pagevisuals->find_all()) > 0)
{
$visual = $this->page->parent->pagevisuals->find_all();
}
// If two levels deep, grandparent page might have visuals
elseif (count($this->page->parent->parent->pagevisuals->find_all()) > 0)
{
$visual = $this->page->parent->parent->pagevisuals->find_all();
}
You can write a loop instead:
$page = $this->page;
$visual = null;
while (!$visual && $page) {
$visual = $page->pagevisuals->find_all();
$page = $page->parent;
}
I believe this is equivalent, and will work no matter how many levels of parents/nesting you have.
You could assign $this->page to a variable and begin the statements with that, for a very slight improvement.
Alternatively, you could create nested ternary statements to assign $visual, but that's certainly not recommended practice.
A recursive approach:
function getVisuals($root) {
$visuals = $root->pagevisuals->find_all();
if(count($visuals) === 0 && isset($root->parent)) {
$visuals = getVisuals($root->parent);
}
return $visuals;
}
$visuals = getVisuals($this->page);
If you have control over whatever class $this->page is an instance of, then you can make it an instance method.
You could make a recursive method to get rid of those nasty conditionals. Also you're calling the find_all() method twice for every conditional branch which doubles the process time.
Here's an attempt at a recursive function (might not work though, recursive functions are always a bit tricky!). Beware of infinite loops.
<?php
$visual = $this->page->find_all_visuals();
class Page {
function find_all_visuals()
{
$found = $this->pagevisuals->find_all();
if (count($found) > 0) {
return $found;
} else if ($this->parent == null) {
return null;
} else {
return $this->parent->find_all_visuals();
}
}
}
?>
You might want make two changes in your code:
Ensure that getVisuals() returns an empty array instead of null in case there are no visuals
Consider making a null-object - a singleton page instance that has no visuals and has itself as a parent. It might have a method like isNull() so you can easily test if a given page is the null page.
If you make the two adjustments, most of the code concerning visuals will become easier to write and debug.
Getting all the visuals for two levels (I assume you don't want recursion):
$visuals = array_merge(
$this->page->pagevisuals->find_all(),
$this->page->parent->pagevisuals->find_all(),
$this->page->parent->parent->pagevisuals->find_all(),
);
Getting the visuals of the page OR of parent OR of grand parent:
($visuals = $this->page->pagevisuals->find_all()) ||
($visuals = $this->page->parent->pagevisuals->find_all()) ||
($visuals = $this->page->parent->parent->pagevisuals->find_all());
Recursive functions would be much simpler too (this is a method to add to the page object):
public function findRecursive(){
$my_visuals = $this->pagevisuals->find_all()
return $this->parent->isNull()?
$my_visuals
: array_merge($my_visuals, $this->parent->findRecursive());
}
$visual = $this->page->pagevisuals->find_all()
or $visual = $this->page->parent->pagevisuals->find_all()
or $visual = $this->page->parent->parent->pagevisuals->find_all();
What do you do if none of them match? In this code it will be set to the last one, which is not the same as what you did. (In your code $visual was not touched if none matched, in this code it will be set to zero. You could add or $visual = -1 or something similar.)
You can make a loop if you want to avoid all the ->parent, but you'll need some terminator.
$el = $this->page;
while(!$visual = $el->pagevisuals->find_all()) {
$el = $el->parent;
}
This could run forever if it never matches, but I don't know enough about your application to suggest a termination condition - you could add a counter, or something else.

A better way to use find with PHP/MongoDB?

I am trying to create a function that checks to see if a user name already exists. I am still trying to get my head wrapped around MongoDB and was wonder what is the best way to approach this? I was going to do some the following (in Code Igniter):
$filter = array ('userName' => $value);
$exists = $md->find($filter);
if ($exist) {
return TRUE
} else {
return FALSE
}
Is there a better way?
Looks about right, here's what I have for mine.
if ($collection->findOne(array("username" => $username)) );
return true;

Categories