0

I am trying to create a class to clean data for a brand before adding it to my database.

As you can see I have added general filters (which can be used elsewhere). On the other hand, some fields will need a personalized cleaning. That's why I created 'function' in my array.

My code is currently functional however the create_function function is deprecated and I would like to remove it but I cannot find an alternative without using eval.

Can you help me find a solution? Thank you.

<?php
class VehMarques
{
    private static $fields_allowed = [
    
    '_id' =>    
    [
        'instanceof' => '\MongoDB\BSON\ObjectID',
    ],
                
    'name' => 
    [
        'function' => 'if(!isset($name) && !isset($age)){return false;}',
    ],
                
    'user' =>
    [
        'required',
        'instanceof' => '\MongoDB\BSON\ObjectID',
    ],
    
    'centre' =>
    [
        'required',
        'instanceof' => '\MongoDB\BSON\ObjectID',
    ],
    
    'time' =>
    [
        'instanceof' => 'MongoDB\BSON\UTCDateTime',
    ],
    
    ];
    
    public static function add(array $fields)
    {
        $fields_options=array();
        foreach(self::$fields_allowed as $key => $val)
        {
            foreach($val as $key1 => $val1)
            {
                if(in_array($val1, array('required')))
                {
                    $fields_options[$val1][$key] = null;
                }
                else
                {
                    $fields_options[$key1][$key] = $val1;
                }
            }
        }
        
        if(!empty(self::$fields_allowed) && !empty(array_diff_key($fields, self::$fields_allowed)))
        {
            return false;
        }
        
        if(!empty($fields_options['function']))
        {
            foreach($fields_options['function'] as $func)
            {
                $func = preg_replace('/\$([a-zA-Z0-9]+)/', '$fields[\'$1\']', $func);
                
                if(create_function('$fields', $func)($fields) === false)
                {
                    return false;
                }
            }
        }
        
        if(!empty($fields_options['required']) && !empty(array_diff_key($fields_options['required'], $fields)))
        {
            return false;
        }
        
        if(!empty($fields_options['instanceof']))
        {
            foreach($fields_options['instanceof'] as $key => $val)
            {
                if(!($fields[$key] instanceof $val))
                {
                    return false;
                }
            }
        }
        
        if(!isset($fields['_id']))
        {
            $fields['_id'] = new \MongoDB\BSON\ObjectID();
        }
        
        if(!isset($fields['time']))
        {
            $fields['time'] = new MongoDB\BSON\UTCDateTime();
        }
        
        return true;
    }
}

$insert_marque = array(
'_id' => new \MongoDB\BSON\ObjectID(),
'name' => 'Test',
'user' => new \MongoDB\BSON\ObjectID(),
'centre' => new \MongoDB\BSON\ObjectID(),
'time' => new MongoDB\BSON\UTCDateTime()
);

var_dump(VehMarques::add($insert_marque));
?>

1 Answers1

0

Never use eval of function that can create executable code from string. It is extremely bad practice.

Use callbacks instead:

class VehMarquesValidator
{
    private $callbacks = [];
    
    public function __construct() 
    {
        $this->callbacks = [
            [$this, 'validateVehMarques']
        ];
    }

    public function validate(array $fields) 
    {
        foreach ($this->callbacks as $callback) {
            if (!call_user_func($callback, $fields)) {
                return false;
            }
        }

        return true;
    }

    private function validateVehMarques(array $fields) 
    {
        if(isset($fields['name'])) {
            return true;
        }
        
        if(isset($fields['age'])) {
            return true;
        }

        return false;
    }            
}

$validator = new VehMarquesValidator();
var_dump($validator->validate([
    'name' => 'Test'
]));

var_dump($validator->validate([
    'no_name' => 'Test'
]));

Try to avoid static methods. It is bad practice too.

Pavol Velky
  • 770
  • 3
  • 9
  • First of all thank you for taking the time to find a solution to my problem. Indeed, it is a totally different approach from what I had thought. I hardly ever used the objects and it helps a lot to see the different ways of using them. Can you tell me why using static methods is bad practice? – Alexis Bonnyaud Jan 01 '21 at 13:27
  • It breaking some OOP principles as polymorphism. You can't use static methods in interface as expected. Other problems are with code debugging. It is more simple to debug code where you are creating instances of class and injecting it to other classes. That way you can tell which class is dependent on your class very quickly. **Bad practice doesn't mean you should not ever use static methods. It means you should consider when to use it and use it for purpose not for laziness.** – Pavol Velky Jan 02 '21 at 09:31