function calling itself - php

again with another problem.
public function __construct() {
$_GET = $this->clean($_GET);
$_POST = $this->clean($_POST);
...
}
public function clean($data) {
if (is_array($data)) {
foreach ($data as $key => $value) {
unset($data[$key]);
$data[$this->clean($key)] = $this->clean($value);
}
} else {
$data = htmlspecialchars($data, ENT_COMPAT, 'UTF-8');
}
return $data;
}
i dont understand why $data[$this->clean($key)] = $this->clean($value); is calling its own function. what is the point of doing this? the advantages
thanks,
daniel

It's a technique called recursion. This particular function descends into the structure until it is dealing with very simple data and sanitizes it all.
Given this:
$arr = array (
'<foo' => array(
'bat' => 'OMGWTFBBQ!!><!?!'
),
'bar' => 'baz'
);
It would start:
is arr an array?
is <foo an array? (no)
<foo becomes <foo
<foo used as a key
is the value of <foo an array? (yes)
Is bat an array? (no)
bat remains as is (still has htmlspecialchars called, but it does not change anything))
Is 'OMGWTFBBQ!!><!?!' an array (no)?
'OMGWTFBBQ!!><!?!' is converted to 'OMGWTFBBQ!!><!?!'
'OMGWTFBBQ!!><!?!' is used for the value for bat.
Is 'bar' an array? (no)
bar returned as is (like bat above)
Is baz an array? (no)
baz returned as is.
You can think of it this way
$arr = array (
'<foo' => array(
'bat' => 'OMGWTFBBQ!!><!?!'
),
'bar' => 'baz'
);
///////////////////////////////////////////
array (
clean('<foo') => array(
'bat' => 'OMGWTFBBQ!!><!?!'
),
'bar' => 'baz'
);
///////////////////////////////////////////
array (
'<foo' => clean( array(
'bat' => 'OMGWTFBBQ!!><!?!'
)),
'bar' => 'baz'
);
///////////////////////////////////////////
array (
'<foo' => array(
clean( 'bat' ) => 'OMGWTFBBQ!!><!?!'
)),
'bar' => 'baz'
);
///////////////////////////////////////////
array (
'<foo' => array(
'bat' => clean( 'OMGWTFBBQ!!><!?!' )
)),
'bar' => 'baz'
);
///////////////////////////////////////////
array (
'<foo' => array(
'bat' => 'OMGWTFBBQ!!><!?!'
)),
clean( 'bar' ) => 'baz'
);
///////////////////////////////////////////
array (
'<foo' => array(
'bat' => 'OMGWTFBBQ!!><!?!'
)),
'bar' => clean( 'baz' )
);
///////////////////////////////////////////
return array (
'<foo' => array(
'bat' => 'OMGWTFBBQ!!><!?!'
)),
'bar' => 'baz'
);

clean function uses htmlspecialchars to clean html chars from string. But if $data is an array it calls itself for cleaning all of its keys and values. This is why clean is recursive.
The advantage of this approach is clean function works for string and array transparently.

It's called recursion.
In your example the $_GET and $_POST arrays may contain elements which are also arrays which themselves can contain arrays (ad infinitum). So you don't know how many sub-arrays you will have to clean up.
To solve this problem the function clean is written in a manner that it calls itself when it occurs a "sub array" while cleaning the current array. It's like a loop just for nested data structures.

Related

unset() in multidimensional array check if key exists first

My array:
$array = array(
'test' => 'hello',
'something' => array(
'sub1' => 'foo'
)
);
I'd like to use:
if(array_key_exists('sub1', $array['something'])
{
unset($array['something']['sub1'];
}
The unset part works, but the if statement returns false while the sub1 item is definitely there. Why is this?
I think you need to reformat your code a little. However, here is the formatted code,
$arr = [
'test' => 'hello',
'something' => [
'sub1' => 'foo'
]
];
if(
is_array($arr['something']) &&
array_key_exists('sub1', $arr['something'])
)
{
unset($arr['something']['sub1']);
}
print_r($arr);
and I am getting following result,
Array
(
[test] => hello
[something] => Array
(
)
)
Can you elaborate on what is it that you want to do ??

Get certain elements of an array by its key

I'm sure there's a function for this:
What I have:
$myArray = array( 'foo' => 123, 'bar' => 456, 'lou' => 789, 'wuh' => 'xyz' );
$iNeed = array( 'foo', 'lou' );
How can I get the key value pairs that $iNeed:
$output = super_magic_function( $iNeed, $myArray );
// output should be array( 'foo' => 123, 'lou' => 789 );
How is that super_magic_function called (native php if possible)
$output = array_intersect_key($myArray, array_flip($iNeed));
If you need it as a function:
function super_magic_function($array, $required) {
return array_intersect_key($array, array_flip($required));
}
Output:
Array
(
[foo] => 123
[lou] => 789
)
Documentation: array_intersect_key(), array_flip()
Demo.

How do I search and replace an entire multi-level array in PHP?

How do I search and replace an entire multi-level array in PHP? As in something like:
$a = array(
'level1' => array(
'level2' => array(
'level3' => 'foo'
)
'level2b' => array(
'level3b' => 'foo'
)
);
So, replace 'foo' with 'bar'.
BACKGROUND: I'm having to do this on a serialized array from a WordPress blog since we're moving this blog to another directory name.
Very simple with array_walk_recursive
array_walk_recursive($a, function (&$val) {
$val = str_replace('foo', 'bar', $val);
});
print_r($a);
Just make sure to use a reference (&$val).
demo: http://codepad.viper-7.com/7L33Fg

Flatten indexed array

I'm trying to insert a PHP array into a mysql database, but am having trouble with this particular array. I'm trying to create a function that takes
array( 0 => array ( 'col1' => 'value', 'col2' => 'value', 'col3' => 'value', 'col4' => value', 'col5' => 'value', 'col6' => array ( 'string' => array ( 'col7' => 'value' , 'col8' => 'value'), ), ),
1 => array ( 'col1' => 'value', 'col2' => 'value', 'col3' => 'value', 'col4' => array ( ), 'col5' => 'value', 'col6' => array ( 'string' => array ( ), ), ),
2 => array ( 'col1' => 'value', 'col2' => 'value', 'col3' => 'value', 'col4' => array ( ), 'col5' => 'value', 'col6' => array ( 'string' => array ( ), ), ), )
and seperates each numbered array and formats it as:
array( 'col1' => 'value', 'col2' => 'value', 'col3' => 'value', 'col4' => 'value', 'col5' => 'value', ['col6' => 'value','col7' => 'value',] )
array( 'col1' => 'value', 'col2' => 'value', 'col3' => 'value', 'col4' => 'value', 'col5' => 'value', ['col6' => 'value','col7' => 'value',] )
array( 'col1' => 'value', 'col2' => 'value', 'col3' => 'value', 'col4' => 'value', 'col5' => 'value', ['col6' => 'value','col7' => 'value',] )
depending on how many rows there are. Keep in mind these conditions:
+8 cols is just an example, the range can fluctuate greatly.
+Cols containing a array must be non existent if it empty, like in [1] and [2], but not [0].
+Any column could contain a empty or full array. if it contains a full array, it needs to be flatten while retaining it's value.
+Some arrays might have greater then 2 nested arrays. (elements)
+Not all of the arrays have nested arrays, they are already formatted correctly. These arrays can not be affected by the PHP function i'm trying to create.
I'm stumped, every function I've created has failed. Thanks everyone in advance.
UPDATE I used Var_export with this function to get the array above.
function flatten($array, $preserve_keys = false)
{
if (!$preserve_keys) {
$array = array_values($array);
}
$flattened_array = array();
foreach ($array as $k => $v) {
$flattened_array[$k] = $v;
if (is_array($v)) {
$flattened_array = array_merge($flattened_array, call_user_func(__FUNCTION__, $v, $preserve_keys));
} elseif ($preserve_keys) {
$flattened_array[$k] = $v;
} else {
$flattened_array[] = $v;
}
}
return (array)$flattened_array;
}
What you need is what's called a recursive function (see this question for more info: What is a RECURSIVE Function in PHP?).
Also it seems that each "col" in the array is a string (and not a number).
What you might want to try is check whether the first (or any) key in the array is numeric.
The code would look something like this:
public function extractArray($myArray){
$extractedArray = array(); // create a new array where all the flattened data will go
$arrayKeys = array_keys($myArray); // grab all the keys from the array
if (is_numeric($arrayKeys[0])): // if the first key is a number (it's nested)
$extractedArray = $myArray[0]; // remove one level of the array by grabbing everything from the first element
extractArray($extractedArray); // run our function again to check if we need to remove another layer
else:
$extractedArray = $myArray; // seems like there are no layers that need to be removed
endif;
return $extractedArray;
}
Edit:
Here is a possible solution for the second part of the problem (extracting values from possible sub-arrays)
Here are the steps we are going to take:
1) Loop through each element in our $extractedArray (from part 1) and see if it is a sub array
2) If it is an array we extract it's contents and place it in a temporary variable (an array for now)
3) We then call ourselves again (recursively) passing it the new temporary variable (until there are no more sub-arrrays left
4) Once we have extracted all the values and flattened them in to a single array, we can then loop through that array and store them as a string (or whatever else we like)
Updated Code
Here is the code:
public function flattenArrayValues($extractedArray){
$extractedValues = array();
foreach($extractedArray as $key => $eA):
if(is_array($eA)): // check whether current element is an array
reset($eA); // go to the first element of the array and grab it
$first_key = key($eA); // ...
$extractedValues[$key] = $eA[$first_key]; // this allows us to preserve the "cols" for each element
flattenArrayValues($extractedValues); //call ourselves again to check whether there are any sub-arrays
endif;
endforeach;
return $extractedValues; // seems like we extracted all the values and flattened them
// if we want we can loop through this new array and build a string out of it etc.
}
Hope this was helpful

Replace certain items within multidimensional array

I have an array that can vary in how many arrays deep there are, for example:
array(
'one' => array(
array(
'something' => 'value'
),
array(
'something2' => 'value2'
),
'another' => 'anothervalue'
),
'two' => array(
array(
'something' => 'value'
),
array(
'something2' => 'value2'
),
'another' => 'anothervalue'
)
)
Now, let's say I want to replace everything with the key 'something'.
Would I need to use a recursive function to iterate through the array? or is there a better way?
Thank you!
Have a look at array_walk_recursive. It may be quite handy in a situation like this.
Here's an example using array_walk_recursive:
$arr = array(
'one' => array(
array('something' => 'value'),
array('something2' => 'value2'),
'another' => 'anothervalue'
),
'two' => array(
array('something' => 'value'),
array('something2' => 'value2'),
'another' => 'anothervalue'
)
);
function update_something(&$item, $key)
{
if($key == 'something')
$item = 'newValue';
}
array_walk_recursive($arr, 'update_something');
If used inside a class the callback method have to add the object along with the function. This is achieved with an array:
array_walk_recursive($arr, array($this, 'update_something'));
This is a function that you can either be used as a global function or you just put it into a class:
/**
* replace any value in $array specified by $key with $value
*
* #return array array with replaced values
*/
function replace_recursive(Array $array, $key, $value)
{
array_walk_recursive($array, function(&$v, $k) use ($key, $value)
{$k == $key && $v = $value;});
return $array;
}
# usage:
$array = replace_recursive($array, 'something', 'replaced');
It's also making use of array_walk_recursive but encapsulated. The key and the value can be specified as function parameters and not hardencoded in some callback, so it's more flexible.

Categories