I have a configuration .php file that contains an array ( it has to be a PHP Array ) that contains something similar to:
<?php
return array(
'api_key' => 'e3awY0HoZr0c6L0791Wl2dA3',
'user' => 'Lequis',
'timeout' => '4'
);
These files are uploaded by users, i'd like to validate that the user doesn't add any malicious code, since these files will only contain an array, i'd like to validate that it is in fact only an array
Edit: see #VolkerK's comment regarding how this doesn't guard against the injection of malicious code.
Like #Jay Blanchard said, it may be better to actually think of a more appropriate data structure such as JSON. If you do want to stick to this structure however, you can use PHP's is_array() (http://php.net/manual/en/function.is-array.php) function to validate that a variable is an array before trying to pass that array to any other functions.
That only validates that you do have an array, and not that your array is in the proper format. To go one step further, you can validate that the array is of the right size using the count() (http://php.net/manual/en/function.count.php) function, these two things combined will ensure that you have an array with the correct number of values stored in the array.
The problem of checking to see whether or not the array values are in the correct format is a different beast. You can run through all of the keys and compare the passed key to an array of acceptable keys like so:
function isValidArr($usrArr){
$apiParams = array('api_key', 'user', 'timeout');
for($i = 0; i < count($usrArr); $i++ {
if(!strcmp($usrArr[$i], $apiParams[$i])) {
return false;
}
}
}
And then to check the values associated with each of the keys, I assume that the api_key is of a specific length or within a range, so you could check against that. For the timeout, you could ensure that the value is an integer. To validate against the username, you could implement a regex to ensure that the value adheres to a specific format.
I'm not sure what you want to check, an array or values?
If array, then, i think you can use simply is_array($arr) func.
If values, then there is a good Symfony component SymfonyOptionsResolver
You can use it like a validator for value types/values etc.
public function configureOptions(OptionsResolver $resolver)
{
// ...
$resolver->setAllowedTypes('host', 'string');
$resolver->setAllowedTypes('port', array('null', 'int'));
}
Or use some normalizer and check value with preg_match:
public function configureOptions(OptionsResolver $resolver)
{
// ...
$resolver->setNormalizer('host', function (Options $options, $value) {
if ('http://' !== substr($value, 0, 7)) {
$value = 'http://'.$value;
}
return $value;
});
}
Check documentation for additional info.
Is that what you're looking for?
Related
I have an HTML form that uses POST to send data to a PHP script. Until now I have not used an array in an HTML form, but this form calls for some fields to be grouped (e.g., price and qty) while other fields remain single input fields (name, email, etc).
I would like to sanitize the input when it is received by the PHP script. With single input fields, I used to loop through the fields like this:
if( !empty($_POST) ) {
foreach( $_POST as $x => $y ) {
$_POST[$x] = htmlspecialchars($y);
$_POST[$x] = trim($y);
}
}
How can I sanitize the input when some of the items are in an array?
Modifying all of the leaf nodes in your multidimensional array is easily done with the native function array_walk_recursive() because it visits all of the "leaf nodes" by design.
Code: (Demo) (or as an anonymous one-liner)
$sweet = ['a' => 'apple ', 'b' => ' "banana" '];
$array = ['sweet' => $sweet, 'test' => " <a href='test'>Test</a>"];
function mySanitizer(&$value) {
$value = htmlspecialchars(trim($value));
}
array_walk_recursive($array, 'mySanitizer');
var_export($array);
Output:
array (
'sweet' =>
array (
'a' => 'apple',
'b' => '"banana"',
),
'test' => '<a href=\'test\'>Test</a>',
)
Notice the use of & on the value parameter. This tells the script to modify the data by reference -- otherwise no changes would persist outside of the scope of array_walk_recursive
How to apply this technique...
To apply this technique to all elements in the $_POST superglobal array, call:
array_walk_recursive($_POST, 'mySanitizer');
Of course, this requires you to write the custom function declaration (function mySanitizer() {...}).
Alternatively, if you don't wish to declare the custom function mySanitizer, then this is all you need to write:
array_walk_recursive($_POST, function(&$value){
$value = htmlspecialchars(trim($value));
});
It is more commonplace to have a return value from most functions, however array_walk_recursive() does not offer return data. For this function to be effective for your requirements, the input array must be directly affected by the custom function that it contains. "Modifying a variable by reference" means that you don't need to overwrite the $_POST variable by assignment (like $_POST = ...). Simply by feeding the input array into the native function, writing & before the $value parameter, then overwriting each encountered $value while iterating, your $_POST variable will be sanitized.
As for how array_walk_recursive() "iterates/loops"... there is a special behavior to enjoy. The function will traverse every level of your array. If it finds an "iterable" element, it will loop through the elements that it contains. If it encounters a non-iterable element (scalar elements might be a string, integer, float, boolean, null) it will execute a function / callback (whatever you command it to) on it.
Another example of a php function that modifies by reference is sort(). You don't make an assignment with this function, you just pass your data through it and when you next access the variable's data, it is already modified.
You need to create a recursive function for this.
function htmlentitiesRecursive($data)
{
if (is_array($data)) {
// If the data is an array, iterate through it and convert each item
foreach ($data as $key => $value) {
$data[$key] = htmlentitiesRecursive($value);
}
return $data;
}
// If the data is a string, convert it into html entities
return is_string($data)
? htmlentities(trim($data))
: $data;
}
Usage:
$_POST = htmlentitiesRecursive($_POST);
I'm working on a simple session manager for my framework. Im trying to setup a more user friendly structure for the session data. Essentially my sessions are stored like this:
$app_name = "Some_App_Name";
$component = "notifications";
$key = "errors";
$value = "There was some error";
$_SESSION[$app_name][$component][$key] = $value;
The problem I am facing is creating this structure through parameters within the session class. I have a set method which should ideally set a session value. The $app_name as listed above is by default added to the session class through the constructor, but I need to find a simple way of taking the parameters passed in within the method and then creating the rest. A simple example:
// Where keys could be: $key1 = notifications, $key2 => "notices"
public static function set($key1,$key2,$value) {
$_SESSION[self::$app_name][$key1][$key2] = $value;
}
The above would work if I always have 4 parameters but in some cases I might only have 2 parameters. I could pass 2 parameters (both being an array) but I'm looking for a more streamlined approach (if such an approach exists).
With the creating of the structure and setting values I also need a similiar way of verifying if the value or last key exists:
// Where keys could be: $key1 = notifications, $key2 => "errors"
public static function exists($key1,$key2) {
if(isset($_SESSION[self::$app_name][$key1][$key2])) {
return true;
}
Any suggestions would greatly be appreciated.
$params = array(
"key1" => "value1",
"key2" => "value2",
"value" => "value"
);
public static function set($params = NULL) //default null if no value is passed
{
if (!self::exists($params)) return false;
$_SESSION[self::$app_name][$params["key1"]][$params["key2"]] = $value;
return true;
}
public static function exists($params = NULL)
{
if(isset($_SESSION[self::$app_name][$params["key1"]][$params["key2"]]))
{
return true;
}
return false;
}
In the light of assisting other members wanting to do something similiar, I want to strongly advise you against using this concept as off the bat it sounds like a good idea but your true issue comes with the management of the array itself. Working straight with the $_SESSION superglobal really is the more powerful option on the basis that:
Even with a parameter in place for say server and component ($_SESSION ['somename']['auth']), what happens when you want to access content from that level from another instance of the object? Say I have another session object instance for $_SESSION ['somename']['errors'] but need to access properties from $_SESSION ['somename']['auth'] but within scope my base within the session array is incorrect.
Adding properties is fine $this->session->add("key","name") but what if you want to append to that array (where name is actually an array and not just a value), or vise versa. Or checking for occurances if $_SESSION['somename']['auth']['key']['name'] actually has another key or value within it?
All and all having worked with this the last couple of days I can definately say that it might not be impossible to write a "fully functional" session manager class but at the end of the day for simplicity it's better to rather just work with the session array directly as it's less code and less issues as you go.
I have a model that runs a query with a bunch of conditions in the SQL. As a result, the model needs to accept a lot of parameters, i.e:
this->model_name->method($param1, $param2, ... )
On the model side, I typically set this up as
function method($param1 = NULL, $param2 = NULL, ... )
Each of those parameters is optional, and use cases will vary around the app. So my question is: at what point (if ever) does it make sense to start passing these parameters to the method via an array, a la:
$params = [
'param1' => 'whatever',
'param2' => 'whatever',
...
]
this->model_name->method($params)
With the end goal being, I suppose, cleaner code, and less instances of method(null, null, null, null, $param) unless that's an okay thing to do.
Most answers have been supportive of the array method (which, generally speaking, I would also agree with), but I'll play devil's advocate and list some negatives:
Documentation is less clear
Most methods of documenting functions/methods will list the parameters of that function individually. For example, a function with a basic DocBlock will look like this:
/**
* A function that accepts an array of params
* #param array $param_array An array of key=>value arguments
*/
function accept_array($param_array = array('key1' => 'first_val', 'key2' => 'second_val')) {
var_dump($param_array);
}
Note how the DocBlock doesn't directly support individual parts of the $param_array, just the array as a whole. In contrast, listing all the arguments individually looks like this:
/**
* A function that 'normal' params
* #param string $key1 First argument
* #param string $key2 Second argument
*/
function accept_normal($key1 = 'first_val', $key2 = 'second_val') {
echo $key1;
echo $key2;
}
This is also a problem if you expect your functions to be fairly self-documenting, as in the first example you're not required to actually list your expected arguments in the function itself.
Default values may not work as expected
'As expected' is probably a bit of a loaded phrase (and this is probably one of the more obvious problems), but take the following:
function accept_array($param_array = array('key1' => 'first_val', 'key2' => 'second_val')) {
var_dump($param_array);
}
accept_array(array('key2' => 'a_different_val'));
Some may expect the var_dump to include the default value of key1 and the new value of key2, but the whole array is replaced, meaning you will need to remember to set default values for each key manually in each function, like so:
function accept_array($param_array = array()) {
if (!isset($param_array['key1'])) { $param_array['key1'] = 'first_val'; }
if (!isset($param_array['key2'])) { $param_array['key2'] = 'second_val'; }
var_dump($param_array);
}
accept_array(array('key2' => 'a_different_val'));
No automatic filtering
Listing the arguments the 'normal' way also gives you a built-in set of filters. Take for example this quick and dirty user search:
/**
* We want to allow searching for users by user_id or email only!
* #param array $param_array
*/
function find_user($param_array = array('user_id' => 0, 'email' => '')) {
foreach ($param_array as $field => $value) {
$this->db->or_where($field, $value);
}
$this->db->get('users');
}
find_user(array('first_name' => 'Joe', 'last_name' => 'Bloggs'));
Without manually adding some 'accepted keys' type validation on the $param_array, a call to the find_user() function can essentially use whatever fields it likes. The simpler version would obviously look like this:
/**
* We want to allow searching for users by user_id or email only!
* #param int $user_id
* #param string $email
*/
function find_user($user_id = 0, $email = '') {
$this->db->or_where('user_id', $user_id);
$this->db->or_where('email', $email);
$this->db->get('users');
}
// No way for me to submit any other fields, they'll just fail when they get to the query
find_user('Joe', 'Bloggs'));
I accept some of these are a bit entry-level and there's probably many more that I missed (feel free to comment with more and I'll copy them into the reply with credit), but hopefully there's enough there to make people think twice about automatically using the 'array method' without thinking about manual validation and documentation etc.
Passing an array of parameters provides a better option for self-documenting your code.
When I use many parameters, I often find myself using a style like:
// do_something_model($enable_option1,$enable_option2,$enable_option3)
do_something_model(FALSE, TRUE, FALSE)
where I carry a comment line with the parameter names to remind myself of how I am
using the model.
In such a case, using an array with meaningfully named keys provides a useful mnemonic.
More recently, I am also using more wrapper functions. For example, I may have my
basic model method do get all my data from a table and this method will have a few
options.
I then define a new method that does a specific task and then invoke the basic method within it using the correct options.
Footnote
I find that if my methods have "too many options", it is better to rethink the purpose of the method and to break it up into two or more specialized methods that are easier to use.
I would recommend the array version as well. Symfony2 also uses this pattern a lot, for instance in rendring templates, creating form classes and creating http responses in general. You just have to make sure you cleanly document all possible parameters.
You could go either route, but an array would definitely keep your methods cleaner. It makes perfect sense to pass the parameters as an array.
Attached code taken from cakephp bakery, where someone uploaded a sample about custom validation rules.
class Contact extends AppModel
{
var $name = 'Contact';
var $validate = array(
'email' => array(
'identicalFieldValues' => array(
'rule' => array('identicalFieldValues', 'confirm_email' ),
'message' => 'Please re-enter your password twice so that the values match'
)
)
);
function identicalFieldValues( $field=array(), $compare_field=null )
{
foreach( $field as $key => $value ){
$v1 = $value;
$v2 = $this->data[$this->name][ $compare_field ];
if($v1 !== $v2) {
return FALSE;
} else {
continue;
}
}
return TRUE;
}
}
In the code, the guy used a foreach to access an array member which he had its name already!
As far as I understand - it's a waste of resources and a bad(even strange) practice.
One more thing about the code:
I don't understand the usage of the continue there. it's a single field array, isn't it? the comparison should happen once and the loop will be over.
Please enlighten me.
In the code, the guy used a foreach to access an array member which he had its name already! As far as I understand - it's a waste of resources and a bad(even strange) practice.
The first parameter is always an array on one key and its value, the second parameter comes from the call to that function, in a block named as the key... So, all you need is to send the key and no need to iterate
The code uses foreach to iterate through $field, which is an array of one key value pair. It all starts when the validation routine invokes identicalFieldValues, passing it two values - $field, which would be an array that looks like:
array (
[email] => 'user entered value 1'
)
The second parameter $compare_field would be set to the string confirm_email.
In this particular case, it doesn't look like it makes a lot of sense to use foreach since your array only has one key-value pair. But you must write code this way because CakePHP will pass an array to the method.
I believe the reason why CakePHP does this is because an array is the only way to pass both the field name and its value. While in this case the field name (email) is irrelevant, you might need in other cases.
What you are seeing here is one of the caveats of using frameworks. Most of the time, they simplify your code. But sometimes you have to write code that you wouldn't write normally just so the framework is happy.
One more thing about the code: I don't understand the usage of the continue there. it's a single field array, isn't it? the comparison should happen once and the loop will be over. Please enlighten me.
Indeed. And since there are no statements in the foreach loop following continue, the whole else block could also be omitted.
A simplified version of this would be:
function identicalFieldValues($field=array(), $compare_field=null)
{
foreach ($field as $field) {
$compare = $this->data[$this->name][$compare_field];
if ($field !== $compare) {
return FALSE;
}
}
return TRUE;
}
And I agree with you, the loop only goes through one iteration when validating the email field. regardless of the field. You still need the foreach because you are getting an array though.
Storing an array submitted from forms stores elements with null values. Is there a way to store only non null fields into the php array?
$_SESSION['items'] = $_POST['items'];
is my current code.
You should take a look at array_filter(). I think it is exactly what you are looking for.
$_SESSION['items'] = array_filter($_POST['items']);
# Cycle through each item in our array
foreach ($_POST['items'] as $key => $value) {
# If the item is NOT empty
if (!empty($value))
# Add our item into our SESSION array
$_SESSION['items'][$key] = $value;
}
Like #Till Theis says, array_filter is definitely the way to go. You can either use it directly, like so:
$_SESSION['items'] = array_filter($_POST['items']);
Which will give you all elements of the array which does not evaluate to false. I.E. you'll filter out both NULL, 0, false etc.
You can also pass a callback function to create custom filtering, like so:
abstract class Util {
public static function filterNull ($value) {
return isset($value);
}
}
$_SESSION['items'] = array_filter($_POST['items'], array('Util', 'filterNull'));
This will call the filterNull-method of the Util class for each element in the items-array, and if they are set (see language construct isset()), then they are kept in the resulting array.